mirror of https://github.com/mkerrisk/man-pages
on_exit.3: Atack variables may be out of scope when exit handler is invoked
Here's a program for doing experiments: /* on_expt_scope_expt.c (C) Michael Kerrisk, 2019, Licensed GNU GPLv2+ */ char *tos; static void exitFunc(int status, void *p) { int efloc; int *xp = (int *) p; printf("====== Entered exit handler\n"); printf("&efloc = %p (0x%llx)\n", (void *) &efloc, (long long) (tos - (char *) &efloc)); printf("xp = %p (value: %d)\n", (void *) xp, *xp); if (*xp != INIT_VALUE) printf("It looks like the variable passed to the exit handler " "has gone out of scope\n"); /* Produce a core dump, which we can examine with GDB to look at the frames on the stack, if desired */ printf("===\n"); printf("About to abort\n"); abort(); } static void recur(int lev, int *xp) { int rloc; int big[65536-12]; /* 12*4 == 48 other bytes allocated on this stack frame */ tos = (char *) &rloc; big[0] = lev; big[0]++; printf("&rloc = %p (%d) (%d)\n", (void *) &rloc, lev, *xp); if (lev > 1) recur(lev - 1, xp); else { printf("exit() from recur()\n"); exit(EXIT_SUCCESS); } } int main(int argc, char *argv[]) { int lev; int *xp; int xx; if (argc < 2) { fprintf(stderr, "Usage: %s {s|h} [how]\n", argv[0]); fprintf(stderr, "\ts => exitFunc() arg is in main() stack\n"); fprintf(stderr, "\th => exitFunc() arg is allocated on heapn"); fprintf(stderr, "\tIf 'how' is not present, then return from main()\n"); fprintf(stderr, "\tIf 'how' is 0, then exit() from main()\n"); fprintf(stderr, "\tIf 'how' is > 0, then make 'how' recursive " "function calls, and then exit()\n"); exit(EXIT_FAILURE); } tos = (char *) &xp; if (argv[1][0] == 'h') { xp = malloc(sizeof(int)); if (xp == NULL) { perror("malloc"); exit(EXIT_FAILURE); } printf("Argument for exitFunc() is allocated on heap\n"); } else { xp = &xx; printf("Argument for exitFunc() is allocated on stack in main()\n"); } *xp = INIT_VALUE; printf("xp = %p (value: %d)\n", (void *) xp, *xp); printf("===\n"); on_exit(exitFunc, xp); if (argc == 2) { printf("return from main\n"); return 0; } lev = atoi(argv[2]); if (lev < 1) { printf("Calling exit() from main\n"); exit(EXIT_SUCCESS); } else { recur(lev, xp); } } Reported-by: Sami Kerola <kerolasa@iki.fi> Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
This commit is contained in:
parent
f92ea96bab
commit
7c17e8f3cb
|
@ -100,6 +100,16 @@ It no longer occurs in Solaris (SunOS 5).
|
|||
Portable application should avoid this function, and use the standard
|
||||
.BR atexit (3)
|
||||
instead.
|
||||
.SH NOTES
|
||||
By the time
|
||||
.I function
|
||||
is executed, stack
|
||||
.RI ( auto )
|
||||
variables may already have gone out of scope.
|
||||
Therefore,
|
||||
.I arg
|
||||
should not be a pointer to a stack variable;
|
||||
it may however be a pointer to a heap variable or a global variable.
|
||||
.SH SEE ALSO
|
||||
.BR _exit (2),
|
||||
.BR atexit (3),
|
||||
|
|
Loading…
Reference in New Issue