exeinvoke.c revision 11622:b08a2a6286f1
1/* 2 * Copyright (c) 2010, 2016, 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 <string.h> 40#include <sys/mman.h> 41#include <stdlib.h> 42#include <sys/ucontext.h> 43#include <setjmp.h> 44#include <unistd.h> 45#include <sys/syscall.h> 46#include <errno.h> 47 48#include <pthread.h> 49 50#define CLASS_PATH_OPT "-Djava.class.path=" 51 52JavaVM* _jvm; 53 54static jmp_buf context; 55 56static int _last_si_code = -1; 57static int _failures = 0; 58static int _rec_count = 0; 59static int _kp_rec_count = 0; 60 61pid_t gettid() { 62 return (pid_t) syscall(SYS_gettid); 63} 64 65static void handler(int sig, siginfo_t *si, void *unused) { 66 _last_si_code = si->si_code; 67 printf("Got SIGSEGV(%d) at address: 0x%lx\n",si->si_code, (long) si->si_addr); 68 longjmp(context, 1); 69} 70 71void set_signal_handler() { 72 static char altstack[SIGSTKSZ]; 73 74 stack_t ss = { 75 .ss_size = SIGSTKSZ, 76 .ss_flags = 0, 77 .ss_sp = altstack 78 }; 79 80 struct sigaction sa = { 81 .sa_sigaction = handler, 82 .sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESETHAND 83 }; 84 85 _last_si_code = -1; 86 87 sigaltstack(&ss, 0); 88 sigemptyset(&sa.sa_mask); 89 if (sigaction(SIGSEGV, &sa, NULL) == -1) { 90 fprintf(stderr, "Test ERROR. Can't set sigaction (%d)\n", errno); 91 exit(7); 92 } 93} 94 95void *run_java_overflow (void *p) { 96 JNIEnv *env; 97 jclass class_id; 98 jmethodID method_id; 99 int res; 100 101 res = (*_jvm)->AttachCurrentThread(_jvm, (void**)&env, NULL); 102 if (res != JNI_OK) { 103 fprintf(stderr, "Test ERROR. Can't attach to current thread\n"); 104 exit(7); 105 } 106 107 class_id = (*env)->FindClass (env, "DoOverflow"); 108 if (class_id == NULL) { 109 fprintf(stderr, "Test ERROR. Can't load class DoOverflow\n"); 110 exit(7); 111 } 112 113 method_id = (*env)->GetStaticMethodID(env, class_id, "printIt", "()V"); 114 if (method_id == NULL) { 115 fprintf(stderr, "Test ERROR. Can't find method DoOverflow.printIt\n"); 116 exit(7); 117 } 118 119 (*env)->CallStaticVoidMethod(env, class_id, method_id, NULL); 120 121 res = (*_jvm)->DetachCurrentThread(_jvm); 122 if (res != JNI_OK) { 123 fprintf(stderr, "Test ERROR. Can't call detach from current thread\n"); 124 exit(7); 125 } 126 return NULL; 127} 128 129void do_overflow(){ 130 int *p = alloca(sizeof(int)); 131 if (_kp_rec_count == 0 || _rec_count < _kp_rec_count) { 132 _rec_count ++; 133 do_overflow(); 134 } 135} 136 137void *run_native_overflow(void *p) { 138 // Test that stack guard page is correctly set for initial and non initial thread 139 // and correctly removed for the initial thread 140 JNIEnv *env; 141 jclass class_id; 142 jmethodID method_id; 143 int res; 144 145 printf("run_native_overflow %ld\n", (long) gettid()); 146 147 res = (*_jvm)->AttachCurrentThread(_jvm, (void **)&env, NULL); 148 if (res != JNI_OK) { 149 fprintf(stderr, "Test ERROR. Can't attach to current thread\n"); 150 exit(7); 151 } 152 153 class_id = (*env)->FindClass (env, "DoOverflow"); 154 if (class_id == NULL) { 155 fprintf(stderr, "Test ERROR. Can't load class DoOverflow\n"); 156 exit(7); 157 } 158 159 method_id = (*env)->GetStaticMethodID (env, class_id, "printAlive", "()V"); 160 if (method_id == NULL) { 161 fprintf(stderr, "Test ERROR. Can't find method DoOverflow.printAlive\n"); 162 exit(7); 163 } 164 165 (*env)->CallStaticVoidMethod (env, class_id, method_id, NULL); 166 167 set_signal_handler(); 168 if (! setjmp(context)) { 169 do_overflow(); 170 } 171 172 if (_last_si_code == SEGV_ACCERR) { 173 printf("Test PASSED. Got access violation accessing guard page at %d\n", _rec_count); 174 } 175 176 res = (*_jvm)->DetachCurrentThread(_jvm); 177 if (res != JNI_OK) { 178 fprintf(stderr, "Test ERROR. Can't call detach from current thread\n"); 179 exit(7); 180 } 181 182 if (getpid() != gettid()) { 183 // For non-initial thread we don't unmap the region but call os::uncommit_memory and keep PROT_NONE 184 // so if host has enough swap space we will get the same SEGV with code SEGV_ACCERR(2) trying 185 // to access it as if the guard page is present. 186 // We have no way to check this, so bail out, marking test as succeeded 187 printf("Test PASSED. Not initial thread\n"); 188 return NULL; 189 } 190 191 // Limit depth of recursion for second run. It can't exceed one for first run. 192 _kp_rec_count = _rec_count; 193 _rec_count = 0; 194 195 set_signal_handler(); 196 if (! setjmp(context)) { 197 do_overflow(); 198 } 199 200 if (_last_si_code == SEGV_ACCERR) { 201 ++ _failures; 202 fprintf(stderr,"Test FAILED. Stack guard page is still there at %d\n", _rec_count); 203 } else if (_last_si_code == -1) { 204 printf("Test PASSED. No stack guard page is present. Maximum recursion level reached at %d\n", _rec_count); 205 } 206 else{ 207 printf("Test PASSED. No stack guard page is present. SIGSEGV(%d) at %d\n", _last_si_code, _rec_count); 208 } 209 210 return NULL; 211} 212 213void usage() { 214 fprintf(stderr, "Usage: invoke test_java_overflow\n"); 215 fprintf(stderr, " invoke test_native_overflow\n"); 216} 217 218 219int main (int argc, const char** argv) { 220 JavaVMInitArgs vm_args; 221 JavaVMOption options[3]; 222 JNIEnv* env; 223 int optlen; 224 char *javaclasspath = NULL; 225 char javaclasspathopt[4096]; 226 227 printf("Test started with pid: %ld\n", (long) getpid()); 228 229 /* set the java class path so the DoOverflow class can be found */ 230 javaclasspath = getenv("CLASSPATH"); 231 232 if (javaclasspath == NULL) { 233 fprintf(stderr, "Test ERROR. CLASSPATH is not set\n"); 234 exit(7); 235 } 236 optlen = strlen(CLASS_PATH_OPT) + strlen(javaclasspath) + 1; 237 if (optlen > 4096) { 238 fprintf(stderr, "Test ERROR. CLASSPATH is too long\n"); 239 exit(7); 240 } 241 snprintf(javaclasspathopt, sizeof(javaclasspathopt), "%s%s", 242 CLASS_PATH_OPT, javaclasspath); 243 244 options[0].optionString = "-Xint"; 245 options[1].optionString = "-Xss328k"; 246 options[2].optionString = javaclasspathopt; 247 248 vm_args.version = JNI_VERSION_1_2; 249 vm_args.ignoreUnrecognized = JNI_TRUE; 250 vm_args.options = options; 251 vm_args.nOptions = 3; 252 253 if (JNI_CreateJavaVM (&_jvm, (void **)&env, &vm_args) < 0 ) { 254 fprintf(stderr, "Test ERROR. Can't create JavaVM\n"); 255 exit(7); 256 } 257 258 pthread_t thr; 259 260 if (argc > 1 && strcmp(argv[1], "test_java_overflow") == 0) { 261 printf("\nTesting JAVA_OVERFLOW\n"); 262 263 printf("Testing stack guard page behaviour for other thread\n"); 264 pthread_create (&thr, NULL, run_java_overflow, NULL); 265 pthread_join (thr, NULL); 266 267 printf("Testing stack guard page behaviour for initial thread\n"); 268 run_java_overflow(NULL); 269 // This test crash on error 270 exit(0); 271 } 272 273 if (argc > 1 && strcmp(argv[1], "test_native_overflow") == 0) { 274 printf("\nTesting NATIVE_OVERFLOW\n"); 275 276 printf("Testing stack guard page behaviour for other thread\n"); 277 pthread_create (&thr, NULL, run_native_overflow, NULL); 278 pthread_join (thr, NULL); 279 280 printf("Testing stack guard page behaviour for initial thread\n"); 281 run_native_overflow(NULL); 282 283 exit((_failures > 0) ? 1 : 0); 284 } 285 286 fprintf(stderr, "Test ERROR. Unknown parameter %s\n", ((argc > 1) ? argv[1] : "none")); 287 usage(); 288 exit(7); 289} 290