]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/runtime/testdata/testprogcgo/stackswitch.c
runtime: clear g0 stack bounds in dropm
[gostls13.git] / src / runtime / testdata / testprogcgo / stackswitch.c
index 2f79cc28ed95104469f88fe64f409863589939aa..3473d5bd57d0569607df6a1feae98913bee24457 100644 (file)
@@ -43,6 +43,8 @@ static ucontext_t uctx_save, uctx_switch;
 
 extern void stackSwitchCallback(void);
 
+char *stack2;
+
 static void *stackSwitchThread(void *arg) {
        // Simple test: callback works from the normal system stack.
        stackSwitchCallback();
@@ -57,7 +59,9 @@ static void *stackSwitchThread(void *arg) {
 
        // Allocate the second stack before freeing the first to ensure we don't get
        // the same address from malloc.
-       char *stack2 = malloc(STACK_SIZE);
+       //
+       // Will be freed in stackSwitchThread2.
+       stack2 = malloc(STACK_SIZE);
        if (stack1 == NULL) {
                perror("malloc");
                exit(1);
@@ -92,6 +96,40 @@ static void *stackSwitchThread(void *arg) {
        }
 
        free(stack1);
+
+       return NULL;
+}
+
+static void *stackSwitchThread2(void *arg) {
+       // New thread. Use stack bounds that partially overlap the previous
+       // bounds. needm should refresh the stack bounds anyway since this is a
+       // new thread.
+
+       // N.B. since we used a custom stack with makecontext,
+       // callbackUpdateSystemStack had to guess the bounds. Its guess assumes
+       // a 32KiB stack.
+       char *prev_stack_lo = stack2 + STACK_SIZE - (32*1024);
+
+       // New SP is just barely in bounds, but if we don't update the bounds
+       // we'll almost certainly overflow. The SP that
+       // callbackUpdateSystemStack sees already has some data pushed, so it
+       // will be a bit below what we set here. Thus we include some slack.
+       char *new_stack_hi = prev_stack_lo + 128;
+
+       if (getcontext(&uctx_switch) == -1) {
+               perror("getcontext");
+               exit(1);
+       }
+       uctx_switch.uc_stack.ss_sp = new_stack_hi - (STACK_SIZE / 2);
+       uctx_switch.uc_stack.ss_size = STACK_SIZE / 2;
+       uctx_switch.uc_link = &uctx_save;
+       makecontext(&uctx_switch, stackSwitchCallback, 0);
+
+       if (swapcontext(&uctx_save, &uctx_switch) == -1) {
+               perror("swapcontext");
+               exit(1);
+       }
+
        free(stack2);
 
        return NULL;
@@ -101,6 +139,9 @@ void callStackSwitchCallbackFromThread(void) {
        pthread_t thread;
        assert(pthread_create(&thread, NULL, stackSwitchThread, NULL) == 0);
        assert(pthread_join(thread, NULL) == 0);
+
+       assert(pthread_create(&thread, NULL, stackSwitchThread2, NULL) == 0);
+       assert(pthread_join(thread, NULL) == 0);
 }
 
 #endif