2

In this simple code should I take care about memory freeing in default case to escape from memory leak or can I use allocated memory? Does longjmp also revert memory allocations?

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

int main(int argc, const char* argv)
{
jmp_buf jmpbuf;

int *p=NULL;

switch(setjmp(jmpbuf)){
case 0:
    p=(int *) malloc(10*sizeof(int));
    printf("%p\n",p);
    longjmp(jmpbuf,1);
    break;
default:
    printf("%p\n",p);
    free(p);
}


return 0;
}
gagikk
  • 33
  • 4
  • 1
    You should initialise `p = NULL` to be sure a call to `free()` will not fail, even is `p = malloc(...)` had never been called. – alk Feb 12 '15 at 09:01
  • I've corrected declaration so p is initialized to NULL. On first attempt it's always case 0 and allocated address is printed, but on second attempt still p points to the old allocated location instead of NULL. I've tried also to move int *p=NULL between switch and case 0 statements. So is it okay to call free on it? Should not it be NULL? I'm testing it with gcc 4.8. – gagikk Feb 12 '15 at 12:09
  • As far as I understand in registers are stored addresses where actual values are stored, and recovering registers does not revert values in memory. How can someone be sure that values are not stored in registers instead of memory? – gagikk Feb 12 '15 at 13:50
  • `malloc()` allocates memory from the heap only. – alk Feb 12 '15 at 16:37

4 Answers4

2

No, longjmp does not revert dynamic memory allocations.

StenSoft
  • 9,369
  • 25
  • 30
2

longjmp will restore the values of the variables "on the stack" (in this case "p"). However, there are two problems with that in this example:

  • in the default case, p has not been assigned a value, and freeing it would be an error.
  • if the example showed p being allocated an example, the memory leak still would not be fixed, because longjmp cannot do anything about that.
Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105
  • "in the default case, p has not been assigned a value, and freeing it would be an error." But it's guaranteed that setjmp() will return 0 when called directly so when we reach default case via `longjmp` the memory has already been allocated (`case 0` assuming malloc succeeded) so why not free that memory as done in the posted code? – rootkea Apr 24 '22 at 05:41
  • The only modification I'll suggest is to declare `p` as `volatile int *p = NULL;` since we're modifying `p` after `setjmp` and before calling `longjmp()` – rootkea Apr 24 '22 at 05:44
0

longjmp() will not deallocate the memory for you, so you'll have to free() it manually. This is one of the complications with using setjmp()/longjmp() to escape deep call stacks, since you have to worry about cleaning up the resources used by any of the parent functions. Note that in your example, you must declare p as volatile (int *volatile p = NULL;) to prevent it from potentially getting clobbered by longjmp(), since it's modified after the setjmp() call (see here for an explanation).

Community
  • 1
  • 1
sevko
  • 1,402
  • 1
  • 18
  • 37
0

This is a perfectly valid program except:

  1. not declaring p as volatile and
  2. declaring argv as char *.

And yes, free() needs to be called after longjmp() if the memory has been allocated before longjmp().

Since it's guaranteed that the return value of setjmp will be 0 on direct execution, we can be sure that memory will be allocated via case 0.

And, if a local variable needs to be changed after setjmp() and before calling longjmp then you need to declare it as volatile to ask compiler to not to optimize and store in registers but to store/load from stack only.

Why? Because when longjmp loads the saved environment it loads program counter, stack pointer and values in registers saved at the time of direct setjmp() call. If compiler optimizes and stores the variable in register after the setjmp() call then longjmp can't access that value since what it has is register values at the time of setjmp call. So we ask compiler to not to save in registers but to save/load from stack only. And since longjmp has stack pointer we get the latest values of accessible variables from the stack.

Updated code:

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

int main(void)
{
    jmp_buf jmpbuf;
    volatile int *p;

    switch (setjmp(jmpbuf)) {
        case 0:
            p = malloc(10 * sizeof(int));
            printf("p = %p\n", (void *)p);
            longjmp(jmpbuf, 1);
            break;
        default:
            printf("p = %p\n", (void *)p);
            free((void *)p);
    }

    return 0;
}
rootkea
  • 1,474
  • 2
  • 12
  • 32