1 /* 2 * Copyright (c) 2010, 2014, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* This code tests the fact that we actually remove stack guard page when calling 26 * JavaThread::exit() i.e. when detaching from current thread. 27 * We overflow the stack and check that we get access error because of a guard page. 28 * Than we detach from vm thread and overflow stack once again. This time we shouldn't 29 * get access error because stack guard page is removed 30 * 31 * Notice: due a complicated interaction of signal handlers, the test may crash. 32 * It's OK - don't file a bug. 33 */ 34 35 #include <assert.h> 36 #include <jni.h> 37 #include <alloca.h> 38 #include <signal.h> 39 #include <sys/mman.h> 40 #include <stdlib.h> 41 #include <sys/ucontext.h> 42 #include <setjmp.h> 43 #include <unistd.h> 44 #include <sys/syscall.h> 45 #include <errno.h> 46 47 #include <pthread.h> 48 49 JavaVM* _jvm; 50 51 static jmp_buf context; 52 53 static int _last_si_code = -1; 54 static int _failures = 0; 55 static int _rec_count = 0; 56 static int _kp_rec_count = 0; 57 58 pid_t gettid() { 59 return (pid_t) syscall(SYS_gettid); 60 } 61 62 static void handler(int sig, siginfo_t *si, void *unused) { 63 _last_si_code = si->si_code; 64 printf("Got SIGSEGV(%d) at address: 0x%lx\n",si->si_code, (long) si->si_addr); 65 longjmp(context, 1); 66 } 67 68 void set_signal_handler() { 69 static char altstack[SIGSTKSZ]; 70 71 stack_t ss = { 72 .ss_size = SIGSTKSZ, 73 .ss_flags = 0, 74 .ss_sp = altstack 75 }; 76 77 struct sigaction sa = { 78 .sa_sigaction = handler, 79 .sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESETHAND 80 }; 81 82 _last_si_code = -1; 83 84 sigaltstack(&ss, 0); 85 sigemptyset(&sa.sa_mask); 86 if (sigaction(SIGSEGV, &sa, NULL) == -1) { 87 fprintf(stderr, "Test ERROR. Can't set sigaction (%d)\n", errno); 88 exit(7); 89 } 90 } 91 92 void *run_java_overflow (void *p) { 93 JNIEnv *env; 94 jclass class_id; 95 jmethodID method_id; 96 int res; 97 98 res = (*_jvm)->AttachCurrentThread(_jvm, (void**)&env, NULL); 99 if (res != JNI_OK) { 100 fprintf(stderr, "Test ERROR. Can't attach to current thread\n"); 101 exit(7); 102 } 103 104 class_id = (*env)->FindClass (env, "DoOverflow"); 105 if (class_id == NULL) { 106 fprintf(stderr, "Test ERROR. Can't load class DoOverflow\n"); 107 exit(7); 108 } 109 110 method_id = (*env)->GetStaticMethodID(env, class_id, "printIt", "()V"); 111 if (method_id == NULL) { 112 fprintf(stderr, "Test ERROR. Can't find method DoOverflow.printIt\n"); 113 exit(7); 114 } 115 116 (*env)->CallStaticVoidMethod(env, class_id, method_id, NULL); 117 118 res = (*_jvm)->DetachCurrentThread(_jvm); 119 if (res != JNI_OK) { 120 fprintf(stderr, "Test ERROR. Can't call detach from current thread\n"); 121 exit(7); 122 } 123 } 124 125 void do_overflow(){ 126 int *p = alloca(sizeof(int)); 127 if (_kp_rec_count == 0 || _rec_count < _kp_rec_count) { 128 _rec_count ++; 129 do_overflow(); 130 } 131 } 132 133 void *run_native_overflow(void *p) { 134 // Test that stack guard page is correctly set for initial and non initial thread 135 // and correctly removed for the initial thread 136 JNIEnv *env; 137 jclass class_id; 138 jmethodID method_id; 139 int res; 140 141 printf("run_native_overflow %ld\n", (long) gettid()); 142 143 res = (*_jvm)->AttachCurrentThread(_jvm, (void **)&env, NULL); 144 if (res != JNI_OK) { 145 fprintf(stderr, "Test ERROR. Can't attach to current thread\n"); 146 exit(7); 147 } 148 149 class_id = (*env)->FindClass (env, "DoOverflow"); 150 if (class_id == NULL) { 151 fprintf(stderr, "Test ERROR. Can't load class DoOverflow\n"); 152 exit(7); 153 } 154 155 method_id = (*env)->GetStaticMethodID (env, class_id, "printAlive", "()V"); 156 if (method_id == NULL) { 157 fprintf(stderr, "Test ERROR. Can't find method DoOverflow.printAlive\n"); 158 exit(7); 159 } 160 161 (*env)->CallStaticVoidMethod (env, class_id, method_id, NULL); 162 163 set_signal_handler(); 164 if (! setjmp(context)) { 165 do_overflow(); 166 } 167 168 if (_last_si_code == SEGV_ACCERR) { 169 printf("Test PASSED. Got access violation accessing guard page at %d\n", _rec_count); 170 } 171 172 res = (*_jvm)->DetachCurrentThread(_jvm); 173 if (res != JNI_OK) { 174 fprintf(stderr, "Test ERROR. Can't call detach from current thread\n"); 175 exit(7); 176 } 177 178 if (getpid() != gettid()) { 179 // For non-initial thread we don't unmap the region but call os::uncommit_memory and keep PROT_NONE 180 // so if host has enough swap space we will get the same SEGV with code SEGV_ACCERR(2) trying 181 // to access it as if the guard page is present. 182 // We have no way to check this, so bail out, marking test as succeeded 183 printf("Test PASSED. Not initial thread\n"); 184 return NULL; 185 } 186 187 // Limit depth of recursion for second run. It can't exceed one for first run. 188 _kp_rec_count = _rec_count; 189 _rec_count = 0; 190 191 set_signal_handler(); 192 if (! setjmp(context)) { 193 do_overflow(); 194 } 195 196 if (_last_si_code == SEGV_ACCERR) { 197 ++ _failures; 198 fprintf(stderr,"Test FAILED. Stack guard page is still there at %d\n", _rec_count); 199 } else if (_last_si_code == -1) { 200 printf("Test PASSED. No stack guard page is present. Maximum recursion level reached at %d\n", _rec_count); 201 } 202 else{ 203 printf("Test PASSED. No stack guard page is present. SIGSEGV(%d) at %d\n", _last_si_code, _rec_count); 204 } 205 206 return NULL; 207 } 208 209 void usage() { 210 fprintf(stderr, "Usage: invoke test_java_overflow\n"); 211 fprintf(stderr, " invoke test_native_overflow\n"); 212 exit(7); 213 } 214 215 216 int main (int argc, const char** argv) { 217 JavaVMInitArgs vm_args; 218 JavaVMOption options[2]; 219 JNIEnv* env; 220 221 printf("Test started with pid: %ld\n", (long) getpid()); 222 223 options[0].optionString = "-Xint"; 224 options[1].optionString = "-Xss328k"; 225 226 vm_args.version = JNI_VERSION_1_2; 227 vm_args.ignoreUnrecognized = JNI_TRUE; 228 vm_args.options = options; 229 vm_args.nOptions = 2; 230 231 if (JNI_CreateJavaVM (&_jvm, (void **)&env, &vm_args) < 0 ) { 232 fprintf(stderr, "Test ERROR. Can't create JavaVM\n"); 233 exit(7); 234 } 235 236 pthread_t thr; 237 238 if (argc > 1 && strcmp(argv[1], "test_java_overflow") == 0) { 239 printf("\nTesting JAVA_OVERFLOW\n"); 240 241 printf("Testing stack guard page behaviour for other thread\n"); 242 pthread_create (&thr, NULL, run_java_overflow, NULL); 243 pthread_join (thr, NULL); 244 245 printf("Testing stack guard page behaviour for initial thread\n"); 246 run_java_overflow(NULL); 247 // This test crash on error 248 exit(0); 249 } 250 251 if (argc > 1 && strcmp(argv[1], "test_native_overflow") == 0) { 252 printf("\nTesting NATIVE_OVERFLOW\n"); 253 254 printf("Testing stack guard page behaviour for other thread\n"); 255 pthread_create (&thr, NULL, run_native_overflow, NULL); 256 pthread_join (thr, NULL); 257 258 printf("Testing stack guard page behaviour for initial thread\n"); 259 run_native_overflow(NULL); 260 261 exit((_failures > 0) ? 1 : 0); 262 } 263 264 fprintf(stderr, "Test ERROR. Unknown parameter %s\n", ((argc > 1) ? argv[1] : "none")); 265 usage(); 266 }