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 detaching 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; 54 static int _failures = 0; 55 56 pid_t gettid() { 57 return (pid_t) syscall(SYS_gettid); 58 } 59 60 static void handler(int sig, siginfo_t *si, void *unused) { 61 _last_si_code = si->si_code; 62 printf("Got SIGSEGV(%d) at address: 0x%lx\n",si->si_code, (long) si->si_addr); 63 longjmp(context, 1); 64 } 65 66 void set_signal_handler() { 67 static char altstack[SIGSTKSZ]; 68 69 stack_t ss = { 70 .ss_size = SIGSTKSZ, 71 .ss_flags = 0, 72 .ss_sp = altstack 73 }; 74 75 struct sigaction sa = { 76 .sa_sigaction = handler, 77 .sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESETHAND 78 }; 79 80 sigaltstack(&ss, 0); 81 sigemptyset(&sa.sa_mask); 82 if (sigaction(SIGSEGV, &sa, NULL) == -1) { 83 perror("sigaction"); 84 } 85 } 86 87 void *run_java_overflow (void *p) { 88 JNIEnv *env; 89 jclass class_id; 90 jmethodID method_id; 91 92 (*_jvm)->AttachCurrentThread(_jvm, (void**)&env, NULL); 93 94 class_id = (*env)->FindClass (env, "DoOverflow"); 95 if (class_id == NULL) { 96 printf("Test ERROR. Can't load class DoOverflow\n"); 97 exit(7); 98 } 99 100 method_id = (*env)->GetStaticMethodID(env, class_id, "printIt", "()V"); 101 if (method_id == NULL) { 102 printf("Test ERROR. Can't find method DoOverflow.printIt\n"); 103 exit(7); 104 } 105 106 (*env)->CallStaticVoidMethod(env, class_id, method_id, NULL); 107 108 (*_jvm)->DetachCurrentThread(_jvm); 109 } 110 111 void do_overflow(){ 112 int *p = alloca(sizeof(int)); 113 do_overflow(); 114 } 115 116 void *run_native_overflow(void *p) { 117 // Test that stack guard page is correctly set for initial and non initial thread 118 // and correctly removed for the initial thread 119 JNIEnv *env; 120 jclass class_id; 121 jmethodID method_id; 122 123 printf("run_native_overflow %ld\n", (long) gettid()); 124 125 (*_jvm)->AttachCurrentThread(_jvm, (void **)&env, NULL); 126 127 class_id = (*env)->FindClass (env, "DoOverflow"); 128 if (class_id == NULL) { 129 printf("Test ERROR. Can't load class DoOverflow\n"); 130 exit(7); 131 } 132 133 method_id = (*env)->GetStaticMethodID (env, class_id, "printAlive", "()V"); 134 if (method_id == NULL) { 135 printf("Test ERROR. Can't find method DoOverflow.printAlive\n"); 136 exit(7); 137 } 138 139 (*env)->CallStaticVoidMethod (env, class_id, method_id, NULL); 140 141 set_signal_handler(); 142 if (! setjmp(context)) { 143 do_overflow(); 144 } 145 146 if (_last_si_code == SEGV_ACCERR) { 147 printf("Test OK. Got access violation accessing guard page\n"); 148 } 149 150 (*_jvm)->DetachCurrentThread(_jvm); 151 152 if (getpid() != gettid()) { 153 // For non-initial thread we doesn't unmap the region but call os::uncommit_memory and keep PROT_NONE 154 // so if host has enough swap space we will get the same SEGV_ACCERR tring to access it 155 // as if the guard page is present. 156 // We have no ways to check this, so bail out, marking test as succeded 157 printf("Test OK. Not initial thread\n"); 158 return NULL; 159 } 160 161 set_signal_handler(); 162 if (! setjmp(context)) { 163 do_overflow(); 164 } 165 166 if (_last_si_code == SEGV_ACCERR) { 167 ++ _failures; 168 printf("Test FAILED. Stack guard page is still there\n"); 169 } 170 else { 171 printf("Test OK. No stack guard page is present\n"); 172 } 173 174 return NULL; 175 } 176 177 int main (int argc, const char** argv) { 178 JavaVMInitArgs vm_args; 179 JavaVMOption options[1]; 180 JNIEnv* env; 181 182 printf("Test started with pid: %ld\n", (long) getpid()); 183 184 options[0].optionString = "-Xss320k"; 185 186 vm_args.version = JNI_VERSION_1_2; 187 vm_args.ignoreUnrecognized = JNI_TRUE; 188 vm_args.options = options; 189 vm_args.nOptions = 1; 190 191 if (JNI_CreateJavaVM (&_jvm, (void **)&env, &vm_args) < 0 ) { 192 printf("Test ERROR. Can't create JavaVM\n"); 193 exit(7); 194 } 195 196 pthread_t thr; 197 198 if (argc > 1 && strcmp(argv[1], "test_java_overflow") == 0) { 199 printf("\nTesting JAVA_OVERFLOW\n"); 200 201 printf("Testing stack guard page behaviour for other thread\n"); 202 pthread_create (&thr, NULL, run_java_overflow, NULL); 203 pthread_join (thr, NULL); 204 205 printf("Testing stack guard page behaviour for initial thread\n"); 206 run_java_overflow(NULL); 207 // This test crash on error 208 return 0; 209 } 210 211 if (argc > 1 && strcmp(argv[1], "test_native_overflow") == 0) { 212 printf("\nTesting NATIVE_OVERFLOW\n"); 213 214 printf("Testing stack guard page behaviour for other thread\n"); 215 pthread_create (&thr, NULL, run_native_overflow, NULL); 216 pthread_join (thr, NULL); 217 218 printf("Testing stack guard page behaviour for initial thread\n"); 219 run_native_overflow(NULL); 220 221 return (_failures > 0) ? 1 : 0; 222 } 223 224 printf("Test ERROR. Unknown parameter should be test_java_overflow or test_native_overflow\n"); 225 exit(7); 226 227 }