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 50void 51NewHandler::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. 75int 76NewHandler::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. 84void *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 93void *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 102void *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. 123void * 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. 136void 137entry_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. 148void 149handle_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. 162jthrowable 163safe_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 // temp solution to reveal all concurrency issues in jtreg and JCK 176 // we will switch it back to silent mode before the release 177 env->ExceptionDescribe(); 178 return xcp; 179 } 180 } 181 182 return NULL; 183} 184 185#ifdef OUTOFMEM_TEST 186 187#include <time.h> 188#include <limits.h> 189 190static void 191rand_alloc_fail(const char *file, int line) throw (std::bad_alloc) 192{ 193 if (alloc_lock == NULL) { // Not yet initialized 194 return; 195 } 196 197 CriticalSection::Lock l(*alloc_lock); 198 199 // Each thread must be seeded individually 200 if (!TlsGetValue(thread_seeded)) { 201 TlsSetValue(thread_seeded, (LPVOID)1); 202 srand((unsigned int)time(NULL)); 203 } 204 205 if (rand() > (int)(RAND_MAX * .999)) { // .1% chance of alloc failure 206 fprintf(stderr, "failing allocation at %s, %d\n", file, line); 207 fprintf(logfile, "%s, %d\n", file, line); 208 fflush(logfile); 209 210 VERIFY(malloc(INT_MAX) == 0); // should fail 211 212 throw std::bad_alloc(); 213 } 214} 215 216void *safe_Malloc_outofmem(size_t size, const char *file, int line) 217 throw (std::bad_alloc) 218{ 219 rand_alloc_fail(file, line); 220 return safe_Malloc(size); 221} 222 223void *safe_Calloc_outofmem(size_t num, size_t size, const char *file, int line) 224 throw (std::bad_alloc) 225{ 226 rand_alloc_fail(file, line); 227 return safe_Calloc(num, size); 228} 229 230void *safe_Realloc_outofmem(void *memblock, size_t size, const char *file, 231 int line) 232 throw (std::bad_alloc) 233{ 234 rand_alloc_fail(file, line); 235 return safe_Realloc(memblock, size); 236} 237 238void * CDECL operator new(size_t size, const char *file, int line) 239 throw (std::bad_alloc) 240{ 241 rand_alloc_fail(file, line); 242 return operator new(size); 243} 244 245#endif 246