Search code examples
csetjmp

How to use longjmp from main function to other functions?


#include <setjmp.h>
#include <stdio.h>

jmp_buf jmp;

int test() {
    setjmp(jmp);
    puts("Birds are crying");
    return 0;
}


int main() {
    longjmp(jmp,1);
    return 0;
}

Above code doesn't work and crashes, why?

I am using the GCC compiler on Windows 10 Pro.


Solution

  • Your usage of longjmp() is invalid, take a look at the documentation:

    longjmp() restores the environment saved by the last call of setjmp()

    You need to call setjmp() first in order to "set" where to jump before calling longjump(). That's why your code doesn't work. It's undefined behavior at best.

    In other words, you cannot just use longjmp() as a simple "jump to global label". It has a different purpose.


    after putting test(); call before the line longjmp it works and print it twice but why does it still crashes?

    Let's again take a look at the documentation:

    setjmp() saves the stack context/environment in env for later use by longjmp(). The stack context will be invalidated if the function which called setjmp() returns.

    You cannot longjmp() to a buffer that was previously set by a function that has now returned. It's invalid. Your usage of setjmp()/longjmp() is really not what those functions are meant for.


    Jumping out to another function isn't really the purpose of setjmp()/longjmp(), their purpose is to save the context and "jump back" to a function that has still not returned (see below example). It's not simple to come up with a meaningful example usage of such functions, since they are meant for advanced usage.

    Here's a correct usage example (while still not that meaningful) from Wikipedia:

    #include <stdio.h>
    #include <setjmp.h>
    
    static jmp_buf buf;
    
    void second() {
        printf("second\n");         // prints
        longjmp(buf,1);             // jumps back to where setjmp was called - making setjmp now return 1
    }
    
    void first() {
        second();
        printf("first\n");          // does not print
    }
    
    int main() {   
        if (!setjmp(buf))
            first();                // when executed, setjmp returned 0
        else                        // when longjmp jumps back, setjmp returns 1
            printf("main\n");       // prints
    
        return 0;
    }