6

I am trying to understand if getcontext/setcontext will work correctly in a specific scenario.

I can see how setcontext() can be used to unwind the stack back to a certain place in history.

#include <stdio.h>
#include <ucontext.h>

int  rollback = 0;
ucontext_t context;

void func(void)
{
    setcontext(cp);
}

int main(void)
{
    getcontext(&context);
    if (rollback == 0)
    {
        printf("getcontext has been called\n");
        rollback++;
        func();
    }
    else
    {
        printf("setcontext has been called\n");
    }
}

But I was wondering if after an unwind you can re-wind back to a place that was in the future? I suppose this depends on the getcontext() call captures a copy of the stack and I can't find the exact details in the documentation.

#include <stdio.h>
#include <ucontext.h>

int  rollback     = 0;
int  backToFuture = 0;
ucontext_t context;
ucontext_t futureContext;

void func(void)
{
    // Some complex calc
    if (some-condition)
    {
        getcontext(&futureContext);  // After returning I want to come back
                                     // here to carry on with my work.
        if (backToFuture == 0)
        {
            setcontext(&context);  // rewind to get stuff-done
        }
    }
    // Finishe work
}

int main(void)
{
    getcontext(&context);
    if (rollback == 0)
    {
        printf("getcontext has been called\n");
        rollback++;
        func();

        // eventually always return here.
    }
    else
    {
        printf("setcontext has been called\n");
        // Do specialized work that needed to be done
        // May involve function calls.
        // 
        // I worry that anything the adds new stack frames
        // will disrupt the saved state of futureContext
        //
        // But without detailed information I can not be sure
        // if this is an allowed senario.
        backToFuture = 1;
        setcontext(&futureContext);
    }
}
Charles
  • 50,943
  • 13
  • 104
  • 142
Martin York
  • 257,169
  • 86
  • 333
  • 562

1 Answers1

4

getcontext doesn't copy stack, it only dumps registers (including stack pointer) and a little context data like signal mask, etc.

When you jump down the stack it invalidates the top context. Even if you won't do any function calls think about the signal handler that can execute there. If you want to jump between two stacks you need to makecontext.

I added variable that demonstrates that your code is invalid:

void func(void)
{
    // Some complex calc
    if (1)
    {
        volatile int neverChange = 1;
        getcontext(&futureContext);  // After returning I want to come back
                                     // here to carry on with my work.
        printf("neverchange = %d\n", neverChange);
        if (backToFuture == 0)
        {
            setcontext(&context);  // rewind to get stuff-done
        }
    }
    // Finishe work
}

On my machine it results in:

getcontext has been called
neverchange = 1
setcontext has been called
neverchange = 32767
zch
  • 14,931
  • 2
  • 41
  • 49
  • Can you provide the correct version of the code in your post using `makecontext`? To be exact, I would like to create a function call out of thin air in a signal handler (which should be executed after handler returns). I also would like the stack unwinding (throw/catch) to work correctly if I throw in this newly created function and try/catch on the outer original context. This requires creating a dynamic function call (stack frame creation) I assume. I am not sure if it is possible with setcontext or not (uc_link in ucontext_t?). – Etherealone Sep 19 '16 at 13:28
  • I managed to use makecontext on this newly created function call but setting uc_link to the signal_handler's last parameter (ucontext_t) does not correctly return to the old context after executing the new function call. (P.S. The aim of stack unwinding in my previous comment is that I want to cleanly abort an offending operation that creates a signal that is not catastrophic). – Etherealone Sep 19 '16 at 13:35
  • @Etherealone, I think that is too complicated for this comment thread, but feel free to link me to a question, should you create one. – zch Sep 19 '16 at 14:42