1 /* 2 * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <new.h> 27 #include <stdio.h> 28 #include "awt_new.h" 29 #include "awt_Toolkit.h" 30 #include "Hashtable.h" 31 32 // Don't want to pull in the redefined allocation functions 33 #undef malloc 34 #undef calloc 35 #undef realloc 36 #undef ExceptionOccurred 37 38 #ifdef OUTOFMEM_TEST 39 #undef safe_Malloc 40 #undef safe_Calloc 41 #undef safe_Realloc 42 #undef new 43 44 static CriticalSection *alloc_lock; 45 static FILE *logfile; 46 static DWORD thread_seeded = TLS_OUT_OF_INDEXES; 47 #endif 48 49 50 void 51 NewHandler::init() { 52 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 53 54 #ifdef OUTOFMEM_TEST 55 alloc_lock = new CriticalSection(); 56 logfile = fopen("java.awt.outofmem.txt", "w"); 57 DASSERT(logfile); 58 thread_seeded = TlsAlloc(); 59 DASSERT(thread_seeded != TLS_OUT_OF_INDEXES); 60 #endif 61 62 // use new handler for operator new and malloc 63 _set_new_mode(1); 64 65 // set the function which will be called when operator new or 66 // malloc runs out of memory 67 _set_new_handler((_PNH)NewHandler::handler); 68 } 69 70 // Called when malloc or operator new runs out of memory. We try to 71 // compact the heap by initiating a Java GC. If the amount of free 72 // memory available after this operation increases, then we return 73 // (1) to indicate that malloc or operator new should retry the 74 // allocation. Returning (0) indicates that the allocation should fail. 75 int 76 NewHandler::handler(size_t) { 77 fprintf(stderr, "java.lang.OutOfMemoryError\n"); 78 return FALSE; 79 } 80 81 // These three functions throw std::bad_alloc in an out of memory condition 82 // instead of returning 0. safe_Realloc will return 0 if memblock is not 83 // NULL and size is 0. safe_Malloc and safe_Calloc will never return 0. 84 void *safe_Malloc(size_t size) throw (std::bad_alloc) { 85 register void *ret_val = malloc(size); 86 if (ret_val == NULL) { 87 throw std::bad_alloc(); 88 } 89 90 return ret_val; 91 } 92 93 void *safe_Calloc(size_t num, size_t size) throw (std::bad_alloc) { 94 register void *ret_val = calloc(num, size); 95 if (ret_val == NULL) { 96 throw std::bad_alloc(); 97 } 98 99 return ret_val; 100 } 101 102 void *safe_Realloc(void *memblock, size_t size) throw (std::bad_alloc) { 103 register void *ret_val = realloc(memblock, size); 104 105 // Special case for realloc. 106 if (memblock != NULL && size == 0) { 107 return ret_val; // even if it's NULL 108 } 109 110 if (ret_val == NULL) { 111 throw std::bad_alloc(); 112 } 113 114 return ret_val; 115 } 116 117 #if !defined(DEBUG) 118 // This function exists because VC++ 5.0 currently does not conform to the 119 // Standard C++ specification which requires that operator new throw 120 // std::bad_alloc in an out of memory situation. Instead, VC++ 5.0 returns 0. 121 // 122 // This function can be safely removed when the problem is corrected. 123 void * CDECL operator new(size_t size) throw (std::bad_alloc) { 124 return safe_Malloc(size); 125 } 126 #endif 127 128 // This function is called at the beginning of an entry point. 129 // Entry points are functions which are declared: 130 // 1. CALLBACK, 131 // 2. JNIEXPORT, 132 // 3. __declspec(dllexport), or 133 // 4. extern "C" 134 // A function which returns an HRESULT (an OLE function) is also an entry 135 // point. 136 void 137 entry_point(void) { 138 if (jvm != NULL) { 139 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 140 if (env != NULL) { 141 env->ExceptionClear(); 142 } 143 } 144 } 145 146 147 // This function is called when a std::bad_alloc exception is caught. 148 void 149 handle_bad_alloc(void) { 150 if (jvm != NULL) { 151 JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 152 if (env != NULL && !env->ExceptionCheck()) { 153 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError"); 154 } 155 } 156 } 157 158 159 // This function is called instead of ExceptionOccurred. It throws 160 // std::bad_alloc if a java.lang.OutOfMemoryError is currently pending 161 // on the calling thread. 162 jthrowable 163 safe_ExceptionOccurred(JNIEnv *env) throw (std::bad_alloc) { 164 jthrowable xcp = env->ExceptionOccurred(); 165 if (xcp != NULL) { 166 env->ExceptionClear(); // if we don't do this, isInstanceOf will fail 167 jint isOutofmem = JNU_IsInstanceOfByName(env, xcp, "java/lang/OutOfMemoryError"); 168 if (isOutofmem > 0) { 169 env->DeleteLocalRef(xcp); 170 throw std::bad_alloc(); 171 } else { 172 env->ExceptionClear(); 173 // rethrow exception 174 env->Throw(xcp); 175 return xcp; 176 } 177 } 178 179 return NULL; 180 } 181 182 #ifdef OUTOFMEM_TEST 183 184 #include <time.h> 185 #include <limits.h> 186 187 static void 188 rand_alloc_fail(const char *file, int line) throw (std::bad_alloc) 189 { 190 if (alloc_lock == NULL) { // Not yet initialized 191 return; 192 } 193 194 CriticalSection::Lock l(*alloc_lock); 195 196 // Each thread must be seeded individually 197 if (!TlsGetValue(thread_seeded)) { 198 TlsSetValue(thread_seeded, (LPVOID)1); 199 srand((unsigned int)time(NULL)); 200 } 201 202 if (rand() > (int)(RAND_MAX * .999)) { // .1% chance of alloc failure 203 fprintf(stderr, "failing allocation at %s, %d\n", file, line); 204 fprintf(logfile, "%s, %d\n", file, line); 205 fflush(logfile); 206 207 VERIFY(malloc(INT_MAX) == 0); // should fail 208 209 throw std::bad_alloc(); 210 } 211 } 212 213 void *safe_Malloc_outofmem(size_t size, const char *file, int line) 214 throw (std::bad_alloc) 215 { 216 rand_alloc_fail(file, line); 217 return safe_Malloc(size); 218 } 219 220 void *safe_Calloc_outofmem(size_t num, size_t size, const char *file, int line) 221 throw (std::bad_alloc) 222 { 223 rand_alloc_fail(file, line); 224 return safe_Calloc(num, size); 225 } 226 227 void *safe_Realloc_outofmem(void *memblock, size_t size, const char *file, 228 int line) 229 throw (std::bad_alloc) 230 { 231 rand_alloc_fail(file, line); 232 return safe_Realloc(memblock, size); 233 } 234 235 void * CDECL operator new(size_t size, const char *file, int line) 236 throw (std::bad_alloc) 237 { 238 rand_alloc_fail(file, line); 239 return operator new(size); 240 } 241 242 #endif