473,320 Members | 2,133 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

exit, atexit and scope

I would like to know if the use of the pointer ref in the function
cleanup() below is valid or if something in the norm prevents this
kind of cross-reference during exit(). I haven't seen anything in the
norm against this, I mean an as-if rule saying "atexit registered
functions are executed as-if they were called from main", making val
out of scope at this point.

a+, ld.

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

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);
}

void test(void) {
int val = 12;
ref = &val;
exit(EXIT_FAILURE);
}

int main(void) {
atexit(cleanup);
test();
return 0;
}
Nov 15 '07 #1
16 3548
Laurent Deniau <La************@gmail.comwrites:
I would like to know if the use of the pointer ref in the function
cleanup() below is valid or if something in the norm prevents this
kind of cross-reference during exit(). I haven't seen anything in the
norm against this, I mean an as-if rule saying "atexit registered
functions are executed as-if they were called from main", making val
out of scope at this point.
You don't mean scope. You are talking about the lifetime of the
variable 'val'. The name 'val' is out of scope during the whole time
exit is doing its job, but the variable, now pointed to by 'ref', still
exists. I think it is safe.
#include <stdio.h>
#include <stdlib.h>

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);
}

void test(void) {
int val = 12;
ref = &val;
exit(EXIT_FAILURE);
}

int main(void) {
atexit(cleanup);
test();
return 0;
}
--
Ben.
Nov 15 '07 #2
Ben Bacarisse <be********@bsb.me.ukwrites:
Laurent Deniau <La************@gmail.comwrites:
>I would like to know if the use of the pointer ref in the function
cleanup() below is valid or if something in the norm prevents this
kind of cross-reference during exit(). I haven't seen anything in the
norm against this, I mean an as-if rule saying "atexit registered
functions are executed as-if they were called from main", making val
out of scope at this point.

You don't mean scope. You are talking about the lifetime of the
variable 'val'. The name 'val' is out of scope during the whole time
exit is doing its job, but the variable, now pointed to by 'ref', still
exists. I think it is safe.
>#include <stdio.h>
#include <stdlib.h>

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);
}

void test(void) {
int val = 12;
ref = &val;
exit(EXIT_FAILURE);
}
I dont think it is safe.
>>
int main(void) {
atexit(cleanup);
test();
test() runs but "int val" is effectively "gone" when the function exits.
> return 0;
}
At this point cleanup is called.

Surely for this to be OK val would need to be a static?

But, I welcome correction.
Nov 15 '07 #3
Laurent Deniau wrote:
I would like to know if the use of the pointer ref in the function
cleanup() below is valid or if something in the norm prevents this
kind of cross-reference during exit(). I haven't seen anything in the
norm against this, I mean an as-if rule saying "atexit registered
functions are executed as-if they were called from main", making val
out of scope at this point.

a+, ld.

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

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);
This test doesn't make sense if it is at all possible that ref is
uninitialised. In this program, it's fine, but consider initialising ref
to NULL at the start of main().
}

void test(void) {
int val = 12;
ref = &val;
exit(EXIT_FAILURE);
}

int main(void) {
atexit(cleanup);
test();
return 0;
}

--
Philip Potter pgp <atdoc.ic.ac.uk
Nov 15 '07 #4
Richard <rg****@gmail.comwrites:
Ben Bacarisse <be********@bsb.me.ukwrites:
>Laurent Deniau <La************@gmail.comwrites:
>>I would like to know if the use of the pointer ref in the function
cleanup() below is valid
<snip>
> I think it is safe.
>>#include <stdio.h>
#include <stdlib.h>

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);
}

void test(void) {
int val = 12;
ref = &val;
exit(EXIT_FAILURE);
}

I dont think it is safe.
>>>
int main(void) {
atexit(cleanup);
test();

test() runs but "int val" is effectively "gone" when the function
exits.
but exit is called before test returns (in this context using the word
'exit' for a function return in going to be a problem!). From my
reading of the standard, the actions of exit -- i.e. the calling of
all registered atexit functions -- take place like a normal function
call. test() would return only after exit is done. I say "would"
because this can happen only when exit returns to its caller -- and
that does not happen (7.20.4.3 p6).
>
>> return 0;
}

At this point cleanup is called.
No. You missed the call of exit in test().

--
Ben.
Nov 15 '07 #5
Ben Bacarisse <be********@bsb.me.ukwrites:
No. You missed the call of exit in test().
Quite correct!

Is it "defined" that val is still there in this case?
Nov 15 '07 #6
Richard <rg****@gmail.comwrites:
Ben Bacarisse <be********@bsb.me.ukwrites:
>No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?
I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.

--
Ben.
Nov 15 '07 #7
Ben Bacarisse <be********@bsb.me.ukwrites:
Richard <rg****@gmail.comwrites:
>Ben Bacarisse <be********@bsb.me.ukwrites:
>>No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?

I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.
Putting it that way I agree. I kind of had it in my mind that calling
exit() was a bit more severe than my_function(). But thinking about it
atoexit would be pretty useless if everything at global scope at least
wasn't available, so why should the stack(!?) for test() have been
folded. Interesting question though.

Nov 15 '07 #8
Philip Potter wrote, On 15/11/07 15:06:
Laurent Deniau wrote:
>I would like to know if the use of the pointer ref in the function
cleanup() below is valid or if something in the norm prevents this
kind of cross-reference during exit(). I haven't seen anything in the
norm against this, I mean an as-if rule saying "atexit registered
functions are executed as-if they were called from main", making val
out of scope at this point.

a+, ld.

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

int *ref;

void cleanup(void) {
if (ref) fprintf(stderr, "val = %d\n", *ref);

This test doesn't make sense if it is at all possible that ref is
uninitialised. In this program, it's fine, but consider initialising ref
to NULL at the start of main().
<snip>

Not required. Any variable defined at file scope or defined as static in
block scope is initialised to an appropriate zero if no initialisation
is provided, so ref is initialised to a null pointer.
--
Flash Gordon
Nov 15 '07 #9
Ben Bacarisse wrote On 11/15/07 11:36,:
Richard <rg****@gmail.comwrites:

>>Ben Bacarisse <be********@bsb.me.ukwrites:

>>>No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?


I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.
A possible implementation of exit():

#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}

.... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...

I don't know off-hand whether any implementations'
exit() functions work this way, but I don't see anything
in the Standard that would forbid it. So I, for one,
will not make use of possibly-deceased `auto' variables
in my atexit() functions, and I'd urge the same course
on others.

--
Er*********@sun.com
Nov 15 '07 #10
Eric Sosman <Er*********@sun.comwrites:
Ben Bacarisse wrote On 11/15/07 11:36,:
>Richard <rg****@gmail.comwrites:

>>>Ben Bacarisse <be********@bsb.me.ukwrites:
No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?


I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.

A possible implementation of exit():

#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}

... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...
Hmmm... OK. But before I fold:

My argument was based on the description of exit which has the rather
suggestive phrase: "First, all functions registered by the atexit
function are called". It can't see how it can do anything of
significance before it does what it must do "first". Is that reading
too much into the operational description of its actions?
I don't know off-hand whether any implementations'
exit() functions work this way, but I don't see anything
in the Standard that would forbid it. So I, for one,
will not make use of possibly-deceased `auto' variables
in my atexit() functions, and I'd urge the same course
on others.
I certainly would not promote the style! It is obviously very fragile
even if I am right (and I am not so sure any more).

--
Ben.
Nov 15 '07 #11
Ben Bacarisse wrote On 11/15/07 17:43,:
Eric Sosman <Er*********@sun.comwrites:

>>Ben Bacarisse wrote On 11/15/07 11:36,:
>>>Richard <rg****@gmail.comwrites:

Ben Bacarisse <be********@bsb.me.ukwrites:

>No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?
I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.

A possible implementation of exit():

#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}

... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...


Hmmm... OK. But before I fold:

My argument was based on the description of exit which has the rather
suggestive phrase: "First, all functions registered by the atexit
function are called". It can't see how it can do anything of
significance before it does what it must do "first". Is that reading
too much into the operational description of its actions?
I think so (obviously ...). If "first" were taken
absolutely literally, as in "The very first executable
statement in exit() must be a call to the most recently
registered atexit() function," that would appear to
outlaw even an `if' to discover if any functions were
registered!

More realistically (perhaps) if exit() looked like

void exit(int status) {
_call_atexit_functions();
fflush(NULL);
_close_open_streams();
_remove_tempfiles();
_really_exit(status);
}

.... then the "first" thing exit() calls is not one of
the exit handlers, but a helper function that in turn
calls those handlers. If you think this implementation
is conforming, then a longjmp() to somewhere else that
does all the same things ought to be conforming, too.

--
Er*********@sun.com
Nov 15 '07 #12
Eric Sosman <Er*********@sun.comwrites:
Ben Bacarisse wrote On 11/15/07 17:43,:
>Eric Sosman <Er*********@sun.comwrites:
<snip>
>> A possible implementation of exit():

#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}

... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...


Hmmm... OK. But before I fold:

My argument was based on the description of exit which has the rather
suggestive phrase: "First, all functions registered by the atexit
function are called". It can't see how it can do anything of
significance before it does what it must do "first". Is that reading
too much into the operational description of its actions?

I think so (obviously ...). If "first" were taken
absolutely literally, as in "The very first executable
statement in exit() must be a call to the most recently
registered atexit() function," that would appear to
outlaw even an `if' to discover if any functions were
registered!
Come now, I said "do anything of significance"!
More realistically (perhaps) if exit() looked like

void exit(int status) {
_call_atexit_functions();
fflush(NULL);
_close_open_streams();
_remove_tempfiles();
_really_exit(status);
}

... then the "first" thing exit() calls is not one of
the exit handlers, but a helper function that in turn
calls those handlers. If you think this implementation
is conforming, then a longjmp() to somewhere else that
does all the same things ought to be conforming, too.
I think if the atexit functions are permitted to be run after
destroying all local variables it deserves a mention, so I am arguing
partly from the significance of an omission.

A final shot: C99 has VLAs, and I would have thought it at least
possible that "rescuing" their contents in an atexit function is
supposed to be allowed. Not a style I'd advocate, but pointing to a
big VLA just before calling a function that might call exit (maybe a
really badly written library function) is a use-case that needs to be
clarified.

--
Ben.
Nov 16 '07 #13
On Thu, 15 Nov 2007 17:18:53 -0500, Eric Sosman <Er*********@sun.com>
wrote in comp.lang.c:
Ben Bacarisse wrote On 11/15/07 11:36,:
Richard <rg****@gmail.comwrites:

>Ben Bacarisse <be********@bsb.me.ukwrites:
No. You missed the call of exit in test().

Quite correct!

Is it "defined" that val is still there in this case?

I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.

A possible implementation of exit():

#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}

... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...
Such an implementation would not be standard conforming. Footnote 10
attached to 5.1.2.3 specifically points out that automatic variables
in main() still exist when if main() calls exit(). It refers to
6.2.4, where paragraph 6 specifically states about automatic objects,
"For such an object that does have a variable length array type, its
lifetime extends from the declaration of the object until execution of
the program leaves the scope of the declaration."

A call to a function, including exit(), does not leave the scope of
objects defined in the calling function.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
Nov 16 '07 #14
On 15 nov, 23:43, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
Eric Sosman <Eric.Sos...@sun.comwrites:
Ben Bacarisse wrote On 11/15/07 11:36,:
Richard <rgr...@gmail.comwrites:
>>Ben Bacarisse <ben.use...@bsb.me.ukwrites:
>>>No. You missed the call of exit in test().
>>Quite correct!
>>Is it "defined" that val is still there in this case?
I can't see why not. If exit() were my_func() and my_func called the
same functions that exit() does it certainly would be. I can't see any
special case text that makes what exit() does special enough to
invalidate this argument.
A possible implementation of exit():
#include <stdlib.h>
#include <setjmp.h>
#include "_implementation_magic.h"
void exit(int code) {
_exit_status = code;
longjmp (_pre_main_jmpbuf, 1);
}
... and Boom! all the program's `auto' variables vanish.
Any atexit-registered functions had better not try to
use them ...

Hmmm... OK. But before I fold:

My argument was based on the description of exit which has the rather
suggestive phrase: "First, all functions registered by the atexit
function are called". It can't see how it can do anything of
significance before it does what it must do "first". Is that reading
too much into the operational description of its actions?
I don't know off-hand whether any implementations'
exit() functions work this way, but I don't see anything
in the Standard that would forbid it. So I, for one,
will not make use of possibly-deceased `auto' variables
in my atexit() functions, and I'd urge the same course
on others.

I certainly would not promote the style! It is obviously very fragile
even if I am right (and I am not so sure any more).
I am not talking to promote this style, but there is cases where this
is required like in "stack unwinding a-la-C++". You have a global
pointer pointing to a linked list of "stacked" pointers to automatic
variables holding critical resources and a proper implementation
should call their destructor before exit()ing. I am open to any
alternative, but the problem is not obvious.

In fact, either C assumes that files are the only critical resource
which need to be cleanup before exit()ing, either the implementation
exibited by E. Sosman is not allowed. I cannot believe that the former
is the intend of the norm.

a+, ld.
Nov 16 '07 #15
Laurent Deniau <La************@gmail.comwrites:
On 15 nov, 23:43, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
<discussion about pointers to automatic data during program termination>
>I certainly would not promote the style! It is obviously very fragile
even if I am right (and I am not so sure any more).

I am not talking to promote this style, but there is cases where this
is required like in "stack unwinding a-la-C++". You have a global
pointer pointing to a linked list of "stacked" pointers to automatic
variables holding critical resources and a proper implementation
should call their destructor before exit()ing. I am open to any
alternative, but the problem is not obvious.
My comment was just a general "avoid this" remark to other readers. I
assumed from your previous posts that you were probably looking into
some automatic C++-style cleanup implementation.

I can offer two ideas (you've probably thought of both!):

(1) Build you own "parallel" stack. Your objects get put here rather
than in automatic storage.

(2) Take over the implementation of exit (yes, not really permitted
but probably safe enough). Of course if you can insist that programs
use your version you don't need to take anything over. Your clean_exit
function can do the cleanup required before calling exit.

--
Ben.
Nov 16 '07 #16
On 16 nov, 18:48, Ben Bacarisse <ben.use...@bsb.me.ukwrote:
Laurent Deniau <Laurent.Den...@gmail.comwrites:
On 15 nov, 23:43, Ben Bacarisse <ben.use...@bsb.me.ukwrote:

<discussion about pointers to automatic data during program termination>
I certainly would not promote the style! It is obviously very fragile
even if I am right (and I am not so sure any more).
I am not talking to promote this style, but there is cases where this
is required like in "stack unwinding a-la-C++". You have a global
pointer pointing to a linked list of "stacked" pointers to automatic
variables holding critical resources and a proper implementation
should call their destructor before exit()ing. I am open to any
alternative, but the problem is not obvious.

My comment was just a general "avoid this" remark to other readers. I
assumed from your previous posts that you were probably looking into
some automatic C++-style cleanup implementation.

I can offer two ideas (you've probably thought of both!):
Right, I did ;-)
(1) Build you own "parallel" stack. Your objects get put here rather
than in automatic storage.
There is two problems with 1). It is inefficient (protection should be
nearly cost-less) so using automatic storage mean that protection is
equivalent to 2-3 machine code moves that is cheap. And you need non-
trivial code to handle bad_alloc-like exceptions since at the same
time you may try to 'push' protected ressources on a dynamically
allocated stack and you may need to enlarge the stack to store this
new reference. This in turn may throw a bad_alloc exception.
(2) Take over the implementation of exit (yes, not really permitted
but probably safe enough). Of course if you can insist that programs
use your version you don't need to take anything over. Your clean_exit
function can do the cleanup required before calling exit.
The code is part of the C Object System which is a general purpose
library to do (true) OO programming in C. I cannot guess all its
possible usage. And there is boundaries what I don't want to cross ;-)

a+, ld.
Nov 19 '07 #17

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Maxwell Hammer | last post by:
An application I am developing executes many threads and then has a "monitor" part that waits for certain events. One of these events causes the application to have to shutdown. On shutdown the...
13
by: Siemel Naran | last post by:
Hi. I posted this question to comp.lang.c++, but am rephrasing it a bit from what I learned and posting to comp.lang.c++.moderated for more insight. So how do I solve my problem? I want it so...
8
by: JKop | last post by:
Let's say that when your program ends (no matter how) that you want a certain block of code to be executed at the end. Here's the code: std::cout << "The program will now end.\n";...
17
by: jwaixs | last post by:
Hello, I was wondering, what's the difference between exit and return in the main() function? For me they both look the same, or aren't they? And if they aren't, which should I use in which...
20
by: lovecreatesbeauty | last post by:
Hello experts, Is the following code snippet legal? If it is, how can exit() do the keyword return a favor and give a return value to the main function? Can a function call (or only this...
19
by: ern | last post by:
Right now I'm using exit(0) to terminate my program. My program is a console .exe application. After the "exit(0)" line of code is encountered, the console application waits for an enter press,...
3
by: carl.dhalluin | last post by:
Hi, I am playing with the atexit module but I don't find a way to see the difference between a script calling sys.exit(<returncode>) and the interpreting arriving at the end of the source code...
9
by: titanandrews | last post by:
Hi All, Is there any way to catch the exit code from someone calling exit(status) and check the value before the program terminates? Just for an idea, the code I'm thinking of is something...
11
by: Rahul | last post by:
Hi Everyone, I have seen code in different styles like main(argc,argv) int argc; char **argv; { if(argc != 2) exit(1); else exit(0);
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.