Topic: setjmp/longjmp and resource leakage.
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Tue, 14 Dec 2004 20:15:10 GMT Raw View
There seems to have been a propagation problem with this response. I have
checked with a moderator and he suggested that I resubmit it. One typo
fixed and a minor clarification added. Line wrap fixed.
Bob Bell wrote:
> "Max T. Woodbury" wrote:
>
>> Bob Bell wrote:
>>
>>> "Max T. Woodbury" wrote:
>>>
>>>> I am well aware the longjmp does not always unwind the stack. The problem
>>>> is that it should be ABLE to do something about resource leakage WHEN it
>>>> does.
>>>
>>>
>>> You want longjmp to somehow be able to tell when it can release
>>> resources and when it can't? How do you propose it determine that?
>>> Supposing this problem is overcome, what would you like longjmp to do
>>> when it can't release resources? Specifically, what should happen if
>>> the programmer thinks one thing, but longjmp is actually doing
>>> something else? How will the programmer know?
>>
>>
>> How does the C++ exception handler do it?
>
>
> OK, I'll tell you how those questions are answered by the C++ exception
> handling mechanism:
[I'm adding an index to your questions here so I can reference them clearly.]
> Q[1]. When can it release resources and when can't it?
> A. It can always release (i.e., it always executes destructors of objects
> on the stack).
For setjmp/longjmp the correct solution would be to execute the active
destructors for the part of the stack being unwound then 'goto' the
return point of the setjmp call.
> Q[2]. What does it do when it can't release resources?
> A. N/A, it always releases.
>
> Q[3]. What happens when the programmer thinks one thing but it actually
> does something else?
> A. N/A, it always releases.
What happens in any language when the programmer thinks one thing should
happen but the code does another? The programmer has to either fix his or
her understanding of the language or get the compiler to do what the
language says it should do.
Since the language does not currently address the interaction between
setjmp/longjmp and destructors explicitly the result is technically
undefined and any program that mixes C and C++ is non-conforming at some
level. This discussion is a speculation on what could be feasibly added
to the standard to define that interaction.
>> Use the same mechanism.
>
>
> The C++ mechanism works because the transfer of control is constrained
> to be towards an enclosing scope. It is impossible to throw a C++ exception
> across scopes or down into a contained scope, so these issues don't come up.
Actually they do come up. You can use a 'goto' across scopes. Both the C
and C++ standard say that doing so invokes 'undefined behavior'. In
other words it admonishes the coder to 'not do that' with no real enforcement
other than saying that such broken code is in fact truly broken. The same
is true of setjmp/longjmp. It should only call destructors if the stack
level changes. The arrangement of such destructors for such changes will be
properly structured. Once the stack level is correct it is just another
form of 'goto' with all the problems that unstructured 'goto's have.
> So again, how will longjmp determine when it can release resources and when
> it can't?
That is a key question. The minimum requirement is to release the
resources that are about to become inaccessible because the stack is being
unwound. Any other resource issues should be handled the same way any
other 'goto' would be handled.
> What will it do when it can't release? What will happen if someone longjmps
> from insider a resource release function that was triggered by a longjmp?
Gag! What happens if a deallocation routine triggered by an exception
throws an exception. IIRC this is 'undefined behavior'. In other
words the answer is the same as Q2 above.
For handlers called because they were explicitly registered, they
should be removed from the registration list before they are called.
If they then do a longjmp, the next least recently registered routine
would get control. Once all the registered routines associated with
the stack segment being unwound have been removed from the list and
called, control would pass to the active C++ object deconstruction
routines. If the registered routine that did the longjmp was a C++
routine, its destructors would be called as part of the set of active
objects in the stack segment being unwound. If a C++ destructor did
a longjmp, the result should be similar to unwinding the stack when
a destructor throws an exception. In other words you could very well
end up with some very unpleasant undefined behavior where destructors
are called twice or not at all...
> Look, the point is really simple: if you seriously expect anyone to
> consider your idea, you've got to describe how it's going to behave.
> How do you expect this to be implemented? What will the
> implementation do in _all_ cases, not just the few cases you think
> are useful? You believe that longjmp can be made to work this way,
> so tell us how. I think we need to see more detail than "just do
> what C++ does."
You're jumping the gun a bit. A lot of this will depend on implementation
details, especially when it integrates C and C++. I'm trying to see if
there is a consensus that the unwind problem can be separated from the
exception problem in C. If it can not, I think the problem is insoluble
since a C solution to the exception problem is going to be incompatible
with the C++ solution to some extent. If it can be separated cleanly,
C and C++ can both use the common unwind solution to implement their
exception handling solutions and there will be at least a chance to get a C
solution to the exception problem without completely screwing up the C++
solution. That common piece should also be used by longjmp. By focusing
on the longjmp problem, addressing the issues associated with exception
incompatibilities can be postponed and some progress can be made.
The solution to the unwind problem is in fact to do what C++ does or would
do. The problem is to find the mapping from setjmp/longjmp to the correct
combination of C++ exception handling and goto handling processing pieces.
Once the proper mixture is identified the details may not need to be
specified since they will already have been specified by the standard in
one place or another.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: jonathan@doves.demon.co.uk (Jonathan Coxhead)
Date: Wed, 15 Dec 2004 05:02:40 GMT Raw View
Max T. Woodbury wrote:
> There seems to have been a propagation problem with this response. I have
> checked with a moderator and he suggested that I resubmit it. One typo
> fixed and a minor clarification added. Line wrap fixed.
>
> Bob Bell wrote:
>
> > "Max T. Woodbury" wrote:
> >
> >> Bob Bell wrote:
> >>
> >>> "Max T. Woodbury" wrote:
> >>>
> >>>> I am well aware the longjmp does not always unwind the stack. The
> problem
> >>>> is that it should be ABLE to do something about resource leakage
> WHEN it
> >>>> does.
I'm wondering how you know when it has unwound the stack? I don't
think this information is always available, as it's only decided at
run-time.
Before the programme does a longjmp(), it might have done a setjmp()
to remember where it is at the moment; then it might jump off (to a
different stack, in effect), and then it might jump back to the original
stack. How do you know if it will or not?
This technique is used to implement coroutines and to help in
implementing threads. Of course, this is highly non-portable, and you
have to be familiar with the relationship between the calling
conventions and the CPU registers. But code like this is written, and
does work.
How could you do what you are suggesting, without breaking such code?
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Thu, 16 Dec 2004 04:57:27 GMT Raw View
Jonathan Coxhead wrote:
> "Max T. Woodbury" wrote:
>
>> I am well aware the longjmp does not always unwind the stack.
>> The problem is that it should be ABLE to do something about
>> resource leakage WHEN it does.
>
> I'm wondering how you know when it has unwound the stack? I don't
> think this information is always available, as it's only decided at
> run-time.
The 'when' I was referring to is at run time. You might be able to
optimize a setjmp/longjmp call out at compile time if the compiler
is told enough about setjmp/longjmp but such knowledge would have to
be conditioned on the inclusion of the <setjmp.h> or <csetjmp> header.
> Before the programme does a longjmp(), it might have done a setjmp()
> to remember where it is at the moment; then it might jump off (to a
> different stack, in effect), and then it might jump back to the original
> stack. How do you know if it will or not?
>
> This technique is used to implement coroutines and to help in
> implementing threads. Of course, this is highly non-portable, and you
> have to be familiar with the relationship between the calling
> conventions and the CPU registers. But code like this is written, and
> does work.
>
> How could you do what you are suggesting, without breaking such code?
Frankly, I don't know. It would depend on the details of the
implementation. I have written coroutines in assembler so I know what
you are talking about. In a single thread environment any HLL
implementation that I can imagine would step way outside the bounds of
the C standard.
The following question would need to be answered:
Q: Does the implementation support mixing C and C++ with exceptions?
If it does, it will already have tackled this problem.
If not, most of the issues with cleaning up the stack during an unwind
are moot.
Since any C specific cleanup would require explicit registration, it
could avoid that problem by either not doing such registrations or
using its own registration procedure or adding knowledge of how the
registration was implemented to the stack switch.
I guess your point is that for some very non-portable implementations
adding C++ stack cleanup could have the effect of requiring a change to
the stack switching code. It could be a real problem. Do you think it
is a significant enough problem to preclude trying to clean up the
resource leakage problem? If so, how would you address the resource
leakage problem?
---------
On the other hand, coroutines are inherently multithreaded. In an
environment where the host environment supports multiple threads,
they are relatively easy to implement and do not need setjmp/longjmp.
In such an environment this change would be a non-issue. (But you
implied that...)
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Sun, 5 Dec 2004 19:53:16 GMT Raw View
Bob Bell wrote:
> max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
>
>> Ron Natalie wrote:
>>
>>> I don't know WHERE you got that assumption. C++ exceptions work just
>>> fine without polymorphism, but you can use that if you like. If you wanted
>>> to do it in C, you could limit the throw/catch types to int (which is
>>> really all longjmp supports anyhow).
>>
>> There are multiple kinds of exceptions all derived from the same basic type.
>> I believe that is polymorphism. You might be able to create A type of exception
>> without polymorphism, but you could not create multiple types of exceptionS without
>> it.
>
> Nothing about exception handling per se demands multiple types of
> exceptions. It's perfectly fine for there to be a single exception
> type, with multiple possible values of that type thrown.
OK. Agreed. The C++ method for distinguish exceptions is peculiar
to C++ and not suitable for use with C. That makes it a major
stumbling block in the way of getting exceptions into C. Because C
does not have polymorphism an exception mechanism for C will be
incompatible with the corresponding C++ mechanism. I think I have
neither the skill, will, influence nor energy to drive such a
discussion to a successful conclusion. I think I might be able to
get the resource leakage problem properly addressed. That is why
I'm a little pissy when exceptions are dragged into the discussion.
If allowed to take over the discussion the problems that come with
them will blur the topic and preclude making any useful changes.
>> Bob Bell wrote:
>>
>>> max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
>>>
>>>> That would be very nice if it can be done without turning C into C++. I get
>>>> the impression that you need polymorphism to do exceptions properly and that
>>>> 'aint gona happen' to C.
>>>
>>> Not true; exceptions and polymorphism are orthogonal. There is no
>>> reason why an exception mechanism couldn't be centered around a
>>> system-defined struct, or even int.
>>
>> To do catch or try you need something like a jmp_buf. That eliminates
>> anything as simple as an int from consideration.
>
> // C++:...
Argh. So I left out the 'in C' qualifier.
>> As I mentioned above
>> there is a connection between exceptions polymorphism.
>
> There's no polymorphism in the previous example, but it is exception
> handling. There is no connection between polymorphism and exception
> handling; you can have either one without the other. As far as I can
> tell, getting stuck on this point simply makes it more difficult to
> add some kind of exception mechanism to C, since C has no
> polymorphism.
But the topic of this thread is setjmp/longjmp, not exceptions...
Exceptions are fine and beautiful but they are only tangential to the
subject. Worse, an exception mechanism for C must be incompatible
with the C++ exception mechanism because the C++ mechanism IS based on
polymorphism. If you really want to try to get exceptions into C,
please have at it. Just move it to another thread!
>>> Further, setjmp/longjmp isn't constrained to jump "up the stack" -- it
>>> could jump to some location that is completely unrelated to a call
>>> site that led to the current function. For example, it could jump to
>>> some other location within the current function; what does it mean to
>>> release resources in this case?
>>
>> Where did you get THAT from? The only way to set up a jmp_buf is to use
>> setjmp and that buffer is invalidated when the routine that called setjmp
>> exits. longjmp is DEFINITELY constrained to only jump "up the stack".
>
> void F(void)
> {
> jmp_buf buf;
>
> setjmp(buf);
>
> /* ... */
>
> longjmp(buf, 1);
> }
>
> This is not a jump "up the stack". The only constraint on longjmp is
> that the jmp_buf must have been initialized by a previous call to
> setjmp; it doesn't matter whether that occurs at a higher nesting
> level or in a caller.
"up the stack" was not a phrase I introduced into this discussion. You did!
I am well aware the longjmp does not always unwind the stack. The problem
is that it should be ABLE to do something about resource leakage WHEN it
does.
> void F(void)
> {
> jmp_buf buf;
>
> if (/* ... */)
> while (/* ... */ ) {
> for (/* ... */) {
> setjmp(buf);
> }
> }
>
> if (/* ... */)
> while (/* ... */ ) {
> for (/* ... */) {
> longjmp(buf);
> }
> }
> }
>
> Again, what does it mean to release resources in this case?
Since there is no stack unwinding in this case, nothing. Further
it may not be necessary to release resources even if the stack is
unwound. What is missing is a way to specify that some resources
will need to be released if the stack is unwound in C. It would be
helpful if you would think about that problem rather than dragging
in irrelevant side issues.
> By returning a jmp_buf from a function, it is even possible to do
> horrible things like jumping into a called function after that
> function has returned.
A program that did that would be non-conforming and the C and C++
standards to not apply to such programs. Discussing such programs
is really off topic for either of these news groups. I am wondering
why you are bringing this kind of irrelevant material into the
discussion.
>>> It seems to me that trying to get setjmp/longjmp to behave like C++
>>> exceptions is a bit like trying to fit a square peg into a round hole.
>>> IMHO, the best thing to do is design a new mechanism.
>>
>> Even with a new mechanism there would still be the problem retrofitting
>> the setjmp/longjmp mechanism.
>>
>> Back to your comments on mechanism:
>>
>> I agree catch/rethrow is a Kluge. There is much more hope on the
>> destructor front.
>>
>> It would be possible to register unwind handlers that would be triggered
>> by the stack level change that longjmp performs.
>
> Longjmp doesn't necessarily perform a stack level change, as shown in
> my previous examples.
ARGH! Why do you think I said 'triggered by'!
>> Those handlers could act
>> as destructors for automatic objects or they could perform other resource
>> management functions like fclose or free. That registration could even
>> be done semi-automatically through alternate interfaces. For example
>> a 'safe fopen' might be named sfopen.
>
> void F(void)
> {
> jmp_buf buf;
>
> if (/* ... */) {
> FILE* fp=sfopen("foo", "r");
>
> while (/* ... */ ) {
> for (/* ... */) {
> setjmp(buf);
> fprintf(fp, "Hello, world.\n");
> }
> }
> fclose(fp);
> }
>
> longjmp(buf);
> }
>
> What would you expect the fprintf to do after getting there via the
> longjmp?
Return EOF because fp does not point to an open file or stream.
>> The support for this would have to
>> go beyond providing a registration mechanism. The resource release
>> functions would have to include a check to see if the resource was
>> registered and remove the registration when the resource was deallocted.
>
> I don't see any other way to do it in C other than some kind of system
> like the one you describe here. However, I'm convinced that
> overloading setjmp/longjmp to do this is entirely the wrong approach,
> because it's too powerful; it allows jumps that are nonsensical from
> the point of view of exception handling.
Would you please NOT use swear words like "nonsensical". C and C++
both contain 'goto' because there are occasions when "sensible"
logical structures are not up to the job of handling unusual conditions.
(In many cases you can remove the 'goto' but the resulting code is
harder to understand and less efficient than the code with the 'goto'.
It also true that lots of 'goto's is a sign of poor understanding and
a lack of forethought. Knowing when to use a 'goto' and when not to is
part of the ART of programming.) setjmp/longjmp is just a bigger 'goto'.
Of course it can be abused. That is the nature of this particular kind
of 'beast'. The fact that you think something is "too powerful" to be
included in the language and expect that argument to be accepted
indicates to me that you are presenting emotional arguments rather than
rational ones. Will you please stop that.
Look, you've coded the longjmp call wrong and ignored the returned value
from setjmp. You also consistently fail to indicate where other error
checks should be included. The result is a very sloppy style of coding.
One that the exceptions mechanism encourages. One of the hard lessons
of programming is that the devil is in the details. I get a sense that
you do not consider this particular lesson important. I may be wrong but
that feeling engenders anger and that anger probably colors my responses.
> A new facility is a much better idea.
so WHAT? Just because you think there is a better way does not mean
that another way might also be used to good effect.
> The programmer needs to be able to describe an "exception context",
> which is a group of "try" statements together with a group of
> "exceptional" statements. If an exception is thrown while executing
> the "try" statements, control transfers to the "exceptional"
> statements, passing along an indication of what the exception was.
And if the the exception paradyme it not appropriate for the environment
are you going to force it on the programmer?
> Implementing this much using setjmp and longjmp is not difficult, and
> gets us as far as the try/catch approach to resource release.
'approach' is good. That is what I am asking about.
> For automatic resource release, we need some mechanism to tell the
> system, when execution transfers from inside the "try" statements to
> the "exception" statements, to execute a "release" function for every
> resource allocated in the "try" statements. I can only see this
> happening in C using some kind of registration facility, but rather
> than providing an alternative to existing functions like "sfopen", I'd
> rather see a single function that looks like this:
>
> void register_resource(void* resource, void (*release)(void*));
I don't particularly like the name. It should return a success/fail
indicator. There should be a note that the stack level from which
the call is made is an implicit parameter. If a subsequent call is
made from a lower stack level, the registration should automatically
be removed. Also, if 'release' is NULL the registration should be
removed. sfopen and fclose would in fact have to call a variant of
this routine that passed the stack level as an explicit parameter.
Details... You've got at least part of the idea that I'm talking
about. I think hashing out that level of detail is a bit premature
at this point which is why I did not present a detailed proposal. I
think defining the scope of the needed changes should come first.
Describing the mechanism used by C++ is also 'on' as would a
description of a C implementation that has tackled this problem.
> This registers a resource and the function that releases it with the
> current try context; whenever control exits the try context it
> executes the release function, whether control exits due to normal
> execution or because an exception is thrown. Example:
>
> FILE* fp = fopen("foo", "r");
> register_resource(fp, &fclose);
>
> This can all be implemented today in C as a series of macros. What
> can't be implemented today, and would require a change to the
> language, is getting return statements to honor the release functions,
> so that executing a return from the middle of a try context will
> execute the registered release functions.
Except for the insistence on the 'try context' you have a fair
handle on the problem. You're missing the fact that the stack level
is also an important parameter. You recognize that there has to be
an unregistration process. But this is still putting the cart before
the horse...
>> In a mixed environment, longjmp and exceptions would share much of the
>> same mechanism.
>
> Modern implementations of C++ exception handling do not use the kind
> of run-time registration discussed in this post; such an
> implementation would be a huge step backwards.
Ah! You speak as though an authority on the subject. I would hear
your wisdom so I can judge for myself. Though I have more than a little
knowledge of how this works, I would like to hear other opinions on how
and more importantly WHY things are the way they are. PLEASE elaborate!
(That sounds much too sarcastic. Please forgive me on that. I really
am interested in any practical information you can provide.)
>> The registration of unwind handlers might even prove
>> to be a cleaner alternative interface than the catch/rethrow mechanism
>> in C++.
>
> If you're suggesting that C++ programmers should use the
> register_resource function (or whatever the mechanism is), that also
> would be a big step backwards, IMO.
>
> void F()
> {
> std::auto_ptr<Foo> p(new Foo());
>
> // ...
> }
>
> vs.
>
> void DeleteFoo(Foo* iFoo)
> {
> delete iFoo;
> }
>
> void F()
> {
> Foo* p(new Foo());
> register_release(p, DeleteFoo);
>
> // ...
> }
Not SHOULD but might or could. A bit of the PERL philosophy seems to
be lacking in this discussion. The bit about more than one way to skin
a cat... That is one reason C and C++ have 'goto's in addition to the
more structured logical constructs.
Consider the case where 'close' is a more appropriate name for the resource
release process than 'delete'. Of course you can probably contrive a way
to make the 'close' part of a 'delete' but that is a distortion similar to
the ones used to eliminate all 'goto's. Having a way to register a 'close'
that would be triggered by a stack unwind would be a useful addition to
both C and C++. Because C does not have anything like auto-pointers, it
becomes something more than 'would be useful' there. I would say that it
is 'necessary' except that C has survived a long time without it. Since I
can not quite justify that contention I will note that a lot of people have
rolled their own variants of this facility and that it is more than a little
tricky to get right. Both of those are characteristics that have been used
successfully for getting a facility or a change to a facility into the
standards.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Sun, 5 Dec 2004 19:56:07 GMT Raw View
Ron Natalie wrote:
> Max T. Woodbury wrote:
>
>> Douglas A. Gwyn wrote:
>>
>>> Execption handling doesn't have to be tied into the
>>> type system.
>>
>> Could you explain that. I believe that you will need an object
>> of some form to communicate the information about an exception to
>> throw/catch/try et al. An object has a type connected to it.
>
> Yes, but right now C++'s longjmp mechanism only passes an integer (and
> even that it doesn't do completely). So, you can assume the type is
> int if you wanted to replace that directly with some exception-like
> system.
longjmp and the associated jmp_buf are a necessary part of an exception
handling procedure in C. Because setjmp can return twice it must
return an indicator distinguishing between the two returns. That does
NOT mean the exception object has to be an integer. Only that it has to
have a jmp_buf associated with it in some way. As long as the first part
of the object passed to setjmp and longjmp is a jmp_buf, it can contain
an arbitrary amount of additional information. Being able to specify
multiple levels of throw/catch and being able to rethrow an exception
implies that the exception type will contain a stack-like set of these
objects so the exception type can not practically be just an int. A
limited design might use an int as an exception selector or index and pass
that value through the setjmp/longjmp mechanism, but calling that index the
exception rather than merely an exception index strikes me as a little silly.
>> The "up the stack" is in quotes because it was the phrase used by
>> Bob Bell. He was claiming you could longjmp off the stack. You
>> snipped the phrase "it could jump to some location that is completely
>> unrelated to a call site that led to the current function" which is
>> simply wrong.
>
> The issue is that longjmp can go back to any place within the same
> function.
Sorry, it can only go back to the return point of a setjmp call.
> C++ exceptions can't escape the try block. For example:
> void foo() {
> {
> setjmp(&jmpbuf) ;
> }
> //...
> {
> longjmp(&jmpbuf);
> }
> }
> is quite possible...the only restriction is that the function can not have
> returned (but you may have exitted the block that has the setjmp.
So what? OK. You could lose some of your context and hang yourself as a
result. The standard warns that that is a problem. C is not a 'molly
coddling' language. < metaphor > It gives you rope. If you choose to hang
your self with it, so be it. It would be nice if there was a standard
stirrup that could be tied to that rope rather than having to hand craft a
loop that might just turn into a noose. </ metaphor > It is an issue of enough
complexity that a standard solution would be useful. But this discussion
seems to be saying that nothing like that should be done. I find that
attitude annoying.
> C++ try/throw however ENFORCES structure. You must have a direct
> path to the catch block. This is not a bad thing in my opinion.
Yep. That is a definite improvement. C++ also had a lot of trouble
working out the details of how to do it right. A little extra work could
have fixed some of the problems with setjmp/longjmp. Not all, but some.
It seems possible that the committee was obsessed with the perfect solution
and failed to examine other alternatives. It is still possible to add a
requirement to a setjmp/longjmp implementation that would make it safer
to use. Failing to even consider such an addition strikes me as short
sighted.
>> The setjmp/longjmp specification is the minimum that was acceptable in 1986
>> when the C standard was first contemplated.
>
> No it can not safely be done.
Huh? A large chunk of connecting logic seems to be missing here.
There does seem to be something you are trying to say so let's just
ignore that.
> Imagine again:
>
> void foo() {
> {
> SomeType o;
> setjmp(&jmpbuf);
> o.function();
> }
> {
> longjmp(&jmpbuf);
> }
> }
>
> In the first block he object o is created and destroyed. The longjmp will send
> conrol back into the middle of the block. What is going to happen to that
> variable?
>
> The object o will be destroyed after the first block exits
So you've decided to hang yourself. That is your privilege. (The fact
that that code is non-conforming in a number of ways is a side issue the
I will agree to ignore if the others taking part in this tread will also
do the same.) You could have created the same kind of mess with a 'goto'
but the compiler probably knows enough about 'goto's to issue a warning.
At best your argument amounts to a request that the same kind of warning
be issued for setjmp as for a labeled statement.
It really has nothing to do with the problem I was trying to discuss.
It would be helpful and should be required that longjmp call any
deconstructors for active automatic objects embedded in the stack segment
that is being unwound. The mechanism for that already exists for
exception processing. Mandating that it be invoked by longjmp before
unwinding the stack does not strike me as imposing an impossible
burden on implementors. Adding a way to specify other cleanup
procedure is a fairly obvious extension that could be included in both
C and C++. I can see that it might be too much work for an embedded
environment but requiring it of a hosted environment seems reasonable
to me.
setjmp/longjmp is FAR from perfect. That does NOT mean that it can
not or should not be improved.
(A note on 'existing art' may be appropriate. I have seen at least
one implementation that does call deconstructors from longjmp. I have
since found the absence of this feature to be annoying in other
environments. I also found that trying to use that capacity from 'C'
left my code way to dependent on that implementation. I can and will
reinvent this particular wheel as many times as I have to, but I know
that there is a better way to do this. One of the better ways requires
changes to the C and C++ standards.)
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Tue, 7 Dec 2004 04:46:31 GMT Raw View
Max T. Woodbury wrote:
> longjmp and the associated jmp_buf are a necessary part of an exception
> handling procedure in C. Because setjmp can return twice it must
> return an indicator distinguishing between the two returns. That does
> NOT mean the exception object has to be an integer.
Excuse me. jmp_buf has nothing to do with what I was talking about.
The C definition of setjmp/longjmp speciifically provides for a single
int value. How that gets communicated between longjmp and setjmp
is an implementation issue. The "incompletely" describes the fact
that the passed value and the "I'm the original call to setjmp" share
the same value so you can't even use all the int values.
The jmp_buf (and whatever C++ does behind the scense to pass whatever
context it needs around) are not the problem. The "thrown" value isn't
the jmp_buf, it's that int that's the second argument to longjmp.
> >
> > The issue is that longjmp can go back to any place within the same
> > function.
>
> Sorry, it can only go back to the return point of a setjmp call.
>
Yes, but what I mean is that it doesn't have to be a descendent of the
block with the set jmp.
>
> So what? OK. You could lose some of your context and hang yourself as a
> result. The standard warns that that is a problem. C is not a 'molly
> coddling' language. < metaphor > It gives you rope.
So you arguments are contradictory. Yes, C++ spent a lot of time trying
to figure out how to do it right. What you are proposing has serious
problems, you start with the premise that you need to unwind the stack
to handle resources and then you say you don't care if it's even possible
to unwind the stack.
>
> So you've decided to hang yourself. That is your privilege. (The fact
> that that code is non-conforming in a number of ways is a side issue the
> I will agree to ignore if the others taking part in this tread will also
> do the same.) You could have created the same kind of mess with a 'goto'
> but the compiler probably knows enough about 'goto's to issue a warning.
> At best your argument amounts to a request that the same kind of warning
> be issued for setjmp as for a labeled statement.
It's not a warning. A C++ program with such a goto is ILLFORMED.
Why you may think it's perfectly fine to introduce more inconsistant
and ill-defined behavior into C, it has no business in C++.
>
> It really has nothing to do with the problem I was trying to discuss.
> It would be helpful and should be required that longjmp call any
> deconstructors for active automatic objects embedded in the stack segment
> that is being unwound.
It has everything to do with what you discussed. Since it can't
be well-defined behavior, there's really no improvement to C++ to do
so.
> The mechanism for that already exists for
> exception processing. Mandating that it be invoked by longjmp before
> unwinding the stack does not strike me as imposing an impossible
> burden on implementors.
Except I've already pointed it out that it is impossible.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Tue, 7 Dec 2004 17:14:16 GMT Raw View
I should point out that I would consider getting requiring
C++ exceptions to propagate with predictable behavior through
C functions in the call stack to be of a higher importance
than reforming setjmp/longjmp.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: terekhov@web.de (Alexander Terekhov)
Date: Wed, 8 Dec 2004 00:45:04 GMT Raw View
Ron Natalie wrote:
>
> I should point out that I would consider getting requiring
> C++ exceptions to propagate with predictable behavior through
> C functions in the call stack to be of a higher importance
> than reforming setjmp/longjmp.
Threaded POSIX has pthread_cleanup_push() and pthread_cleanup_pop().
The things is meant to be integrated with exceptions. Scoped guard
macros, you know.
regards,
alexander.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Wed, 8 Dec 2004 00:44:57 GMT Raw View
Ron Natalie wrote:
> I should point out that I would consider getting requiring
> C++ exceptions to propagate with predictable behavior through
> C functions in the call stack to be of a higher importance
> than reforming setjmp/longjmp.
Agreed. There should at least be defined behavior
when exception unwinding ends up in C code.
At least, a call to Terminate.
John Nagle
Animats
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Wed, 8 Dec 2004 03:38:24 GMT Raw View
From: "" <belvis@pacbell.net>
Newsgroups: comp.std.c, comp.std.c++
Subject: Re: setjmp/longjmp and resource leakage.
Date: Mon, 06 Dec 2004 20:48:05 -0800
"Max T. Woodbury" wrote:
> Bob Bell wrote:
>
> > max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
> >> Bob Bell wrote:
> >>
> >>> Further, setjmp/longjmp isn't constrained to jump "up the stack" -- it
> >>> could jump to some location that is completely unrelated to a call
> >>> site that led to the current function. For example, it could jump to
> >>> some other location within the current function; what does it mean to
> >>> release resources in this case?
> >>
> >> Where did you get THAT from? The only way to set up a jmp_buf is to use
> >> setjmp and that buffer is invalidated when the routine that called setjmp
> >> exits. longjmp is DEFINITELY constrained to only jump "up the stack".
> >
> > void F(void)
> > {
> > jmp_buf buf;
> >
> > setjmp(buf);
> >
> > /* ... */
> >
> > longjmp(buf, 1);
> > }
> >
> > This is not a jump "up the stack". The only constraint on longjmp is
> > that the jmp_buf must have been initialized by a previous call to
> > setjmp; it doesn't matter whether that occurs at a higher nesting
> > level or in a caller.
>
> "up the stack" was not a phrase I introduced into this discussion. You did!
So perhaps the problem here is that it wasn't clear what I meant by "up
the stack." I meant "to an enclosing scope". This could mean
transferring control to a caller, or it could be an enclosing scope in
the current function. Without limiting the transfer of control in this
way, it's hard to imagine how resources can be cleaned up reliably.
> I am well aware the longjmp does not always unwind the stack. The problem
> is that it should be ABLE to do something about resource leakage WHEN it
> does.
You want longjmp to somehow be able to tell when it can release
resources and when it can't? How do you propose it determine that?
Supposing this problem is overcome, what would you like longjmp to do
when it can't release resources? Specifically, what should happen if
the programmer thinks one thing, but longjmp is actually doing
something else? How will the programmer know?
Is this kind of complexity and fragility really better than a new
mechanism that could be designed to ALWAYS transfer control
appropriately?
> > void F(void)
> > {
> > jmp_buf buf;
> >
> > if (/* ... */)
> > while (/* ... */ ) {
> > for (/* ... */) {
> > setjmp(buf);
> > }
> > }
> >
> > if (/* ... */)
> > while (/* ... */ ) {
> > for (/* ... */) {
> > longjmp(buf);
> > }
> > }
> > }
> >
> > Again, what does it mean to release resources in this case?
>
> Since there is no stack unwinding in this case, nothing. Further
> it may not be necessary to release resources even if the stack is
> unwound. What is missing is a way to specify that some resources
> will need to be released if the stack is unwound in C. It would be
> helpful if you would think about that problem rather than dragging
> in irrelevant side issues.
The issue is whether setjmp/longjmp are appropriate for releasing
resources. I claim they aren't, and my reasons aren't "side issues."
> >> Those handlers could act
> >> as destructors for automatic objects or they could perform other resource
> >> management functions like fclose or free. That registration could even
> >> be done semi-automatically through alternate interfaces. For example
> >> a 'safe fopen' might be named sfopen.
> >
> > void F(void)
> > {
> > jmp_buf buf;
> >
> > if (/* ... */) {
> > FILE* fp=sfopen("foo", "r");
> >
> > while (/* ... */ ) {
> > for (/* ... */) {
> > setjmp(buf);
> > fprintf(fp, "Hello, world.\n");
> > }
> > }
> > fclose(fp);
> > }
> >
> > longjmp(buf);
> > }
> >
> > What would you expect the fprintf to do after getting there via the
> > longjmp?
>
> Return EOF because fp does not point to an open file or stream.
I think you missed the point: sfopen (and other such "safe" calls) will
never be safe as long as the programmer can jump past them.
> >> The support for this would have to
> >> go beyond providing a registration mechanism. The resource release
> >> functions would have to include a check to see if the resource was
> >> registered and remove the registration when the resource was deallocted.
> >
> > I don't see any other way to do it in C other than some kind of system
> > like the one you describe here. However, I'm convinced that
> > overloading setjmp/longjmp to do this is entirely the wrong approach,
> > because it's too powerful; it allows jumps that are nonsensical from
> > the point of view of exception handling.
>
> Would you please NOT use swear words like "nonsensical". C and C++
> both contain 'goto' because there are occasions when "sensible"
> logical structures are not up to the job of handling unusual conditions.
> (In many cases you can remove the 'goto' but the resulting code is
> harder to understand and less efficient than the code with the 'goto'.
> It also true that lots of 'goto's is a sign of poor understanding and
> a lack of forethought. Knowing when to use a 'goto' and when not to is
> part of the ART of programming.) setjmp/longjmp is just a bigger 'goto'.
> Of course it can be abused. That is the nature of this particular kind
> of 'beast'. The fact that you think something is "too powerful" to be
> included in the language and expect that argument to be accepted
> indicates to me that you are presenting emotional arguments rather than
> rational ones. Will you please stop that.
You seem to be misunderstanding almost every point I'm making. I didn't
say that anything is too powerful to be included in the language; I
said that setjmp and longjmp are too powerful to implement the behavior
you're after. In order to perform some kind of stack walkback and
release resources, you need a facility that walks up the stack. Longjmp
is inappropriate because it doesn't do that; it can jump to any
previously executed setjmp call, whether that corresponds to a point
which makes sense for resource release or not.
> > The programmer needs to be able to describe an "exception context",
> > which is a group of "try" statements together with a group of
> > "exceptional" statements. If an exception is thrown while executing
> > the "try" statements, control transfers to the "exceptional"
> > statements, passing along an indication of what the exception was.
>
> And if the the exception paradyme it not appropriate for the environment
> are you going to force it on the programmer?
I'm not forcing anything on anyone, just tossing out ideas. It seems to
me that if the programmer wants the stack unwound in order to release
resources, he's got to tell the system where he wants it unwound to,
what he wants done during unwinding, and when it should occur.
> >> In a mixed environment, longjmp and exceptions would share much of the
> >> same mechanism.
> >
> > Modern implementations of C++ exception handling do not use the kind
> > of run-time registration discussed in this post; such an
> > implementation would be a huge step backwards.
>
> Ah! You speak as though an authority on the subject. I would hear
> your wisdom so I can judge for myself. Though I have more than a little
> knowledge of how this works, I would like to hear other opinions on how
> and more importantly WHY things are the way they are. PLEASE elaborate!
> (That sounds much too sarcastic. Please forgive me on that. I really
> am interested in any practical information you can provide.)
Consider this function:
void F()
{
Foo f;
Bar b;
// ...
}
If the function throws an exception, and that exception passes up
through F(), the f and b objects must be destroyed by having their
destructors executed. This can be accomplished by creating a table
indexed by program counter that describes the cleanup actions that
should be taken if an exception is thrown from any particular point in
the function. Here's F() again with comments signficant points in the
function followed by a corresponding exception table:
void F()
{
// 1
Foo f;
// 2
Bar b;
// 3
// ...
}
PC Section Walkback Actions
------------------------------
1 nothing
2 destroy f
3 destroy f and b
No matter how complex a function is, such a table can always be
determined at compile time. The main advantage of this approach is that
it adds no runtime overhead when an exception is not thrown. In
particular, no registration of the destruction functions is needed --
the Foo constructor runs to construct f, then the Bar constructor runs
to construct b, then the rest of the function runs.
If an exception is thrown somewhere, then as control passes up through
F(), the point inside F() through which the exception passes is looked
up in the table to see what needs to be done. Suppose an exception is
thrown while constructing f; control is in section 1, so according to
the table, nothing needs to be done. If an exception is thrown while
constructing b, however, control is in section 2, so f must be
destroyed.
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dave@boost-consulting.com (David Abrahams)
Date: Wed, 8 Dec 2004 22:36:00 GMT Raw View
John Nagle wrote:
> Ron Natalie wrote:
>
>> I should point out that I would consider getting requiring
>> C++ exceptions to propagate with predictable behavior through
>> C functions in the call stack to be of a higher importance
>> than reforming setjmp/longjmp.
>
> Agreed. There should at least be defined behavior
> when exception unwinding ends up in C code.
> At least, a call to Terminate.
For that, you need to change the 'C' standard, not the C++ one.
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Tue, 30 Nov 2004 17:46:32 GMT Raw View
The success/failure indicator thread has drifted into a discussion of exception
and resource leakage when longjmp is used. I'm starting a new thread for it.
This is an old problem with the setjmp/longjmp design. Part of the problem can
be managed with jacket routines for the resource allocators like malloc and fopen.
(You also need cleanup jackets for free and fclose. Note the term 'like'. This
is not a complete list and is not intended to be.) Most of the rest can be
managed with a jacket for longjmp. What can not be handled properly is the little
bit of extra code needed in setjmp. You have to prefix every setjmp call with a
call to a setjmp helper routine.
This suggests that an 'onsetjmp' function similar to 'atexit' would be a useful
addition to the standard. (An 'onlongjmp' routine would also be useful for those
places where 3rd party code uses longjmp and you can not slip the jacket on all
longjmp calls. Standardizing the interface and function of the longjmp safe
resource allocators would also be useful but goes beyond the minimal change
needed to make this work cleanly.)
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Tue, 30 Nov 2004 18:27:32 GMT Raw View
Max T. Woodbury wrote:
> The success/failure indicator thread has drifted into a discussion of exception
> and resource leakage when longjmp is used. I'm starting a new thread for it.
The feature you are asking for is already accomplished by C++'s exception
mechanism.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Wed, 1 Dec 2004 02:51:45 GMT Raw View
Ron Natalie wrote:
>
> Max T. Woodbury wrote:
> > The success/failure indicator thread has drifted into a discussion of exception
> > and resource leakage when longjmp is used. I'm starting a new thread for it.
>
> The feature you are asking for is already accomplished by C++'s exception
> mechanism.
That is correct for C++ exceptions. It does not exist for setjmp/longjmp.
setjmp/longjmp need to be augmented in a way that will not break extant
code. Do you have any suggestions on how to do that?
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe")
Date: Wed, 1 Dec 2004 06:00:53 GMT Raw View
>> The feature you are asking for is already accomplished by C++'s exception
>> mechanism.
>
> That is correct for C++ exceptions. It does not exist for setjmp/longjmp.
> setjmp/longjmp need to be augmented in a way that will not break extant
> code. Do you have any suggestions on how to do that?
When you have the C++ execpetion mechanism, why bother?
longjmp would have to respect any objects on the stack and call their
destructors.
I find it strange that when reading between the lines of the C++ standard,
"undefined behaviour" means "don't taste this forbidden fruit", then you can
guarantee that there will be programmers who raise the question, "I want to
taste the forbidden fruit. How can I do it without paying any penalties?".
Ho hum, definition of humanity I suppose.
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Dan.Pop@cern.ch (Dan Pop)
Date: Wed, 1 Dec 2004 20:22:52 GMT Raw View
In <41ad36f0$0$3113$cc9e4d1f@news.dial.pipex.com> sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe") writes:
>>> The feature you are asking for is already accomplished by C++'s exception
>>> mechanism.
>>
>> That is correct for C++ exceptions. It does not exist for setjmp/longjmp.
>> setjmp/longjmp need to be augmented in a way that will not break extant
>> code. Do you have any suggestions on how to do that?
>
>When you have the C++ execpetion mechanism, why bother?
Look at the Newsgroups line. You don't have *anything* resembling the C++
exception mechanism in standard C.
I've no idea why this new thread was cross-posted to comp.std.c++, since
the issue doesn't make much sense there.
Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
Currently looking for a job in the European Union
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: pornin@nerim.net (Thomas Pornin)
Date: Wed, 1 Dec 2004 20:22:10 GMT Raw View
According to Stephen Howe <sjhoweATdialDOTpipexDOTcom@eu.uu.net>:
> When you have the C++ execpetion mechanism, why bother?
It can be said that C++ is such as it is now because Stroustrup took
great pain to define a language with backward compatibility to C;
I mean that most C source code can be fed to a C++ compiler and
expected to work as-is.
Making setjmp() and longjmp() compatible with C++ extensions would
only follow the same reasoning. I don't say that it should be done
(it is probably quite tricky to do it properly), nor do I claim that
this exercise would be useful (for new code, C++ exceptions should
be used). But at least there is some logic behind.
--Thomas Pornin
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Wed, 1 Dec 2004 23:04:36 GMT Raw View
Thomas Pornin wrote:
> It can be said that C++ is such as it is now because Stroustrup took
> great pain to define a language with backward compatibility to C;
> I mean that most C source code can be fed to a C++ compiler and
> expected to work as-is.
I dispute all of these statements. It's rare that I have C code that
works just fine in C++ without some small amount of editing. While there
is a lot of backwards compatibility to make C palatable to the masses
(especially when it comes to performance), Bjarne was just as
prone to do things "RIGHT" in C++ when they were in his mind wrong
in C.
>
> Making setjmp() and longjmp() compatible with C++ extensions would
> only follow the same reasoning. I don't say that it should be done
> (it is probably quite tricky to do it properly), nor do I claim that
> this exercise would be useful (for new code, C++ exceptions should
> be used). But at least there is some logic behind.
>
If you have a 100% C++ application, there's NO LOGIC to doing it.
The only place this might be the least bit useful is when operating
in a mixed C and C++ environment. It will certainly take collusion
between the two languages in that case (C++ can not unilaterally
assert this compatiblity). So if C is going to have to change things,
perhaps it should do it right.
Setjmp/longjmp has long been an implementation pain in the butt. When
it was originally implemented on PDP-11's, it was real simple, all you
had to do was save the stack pointer a couple of other registers and restore
them. However, I've wrapped my head around other implemetations where there
was more to do (almost akin to a C++ stack unwind) to get these to work
without leaking resources all over the place. The whole concept is
kludgy (as indicated by it's original definition "a non-local goto.").
Lets keep the structured languages structured.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Thu, 2 Dec 2004 05:35:17 GMT Raw View
Max T. Woodbury wrote:
> That is correct for C++ exceptions. It does not exist for setjmp/longjmp.
> setjmp/longjmp need to be augmented in a way that will not break extant
> code. Do you have any suggestions on how to do that?
>
The point I was trying to make is that C++ has no need for setjmp/longjmp.
If we were going to extend C and C++, it would be better to fix C to have
a reasonable exception strategy rather than the rather adhoc codification
of setjmp/longjmp library functions.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: DAGwyn@null.net ("Douglas A. Gwyn")
Date: Thu, 2 Dec 2004 06:51:35 GMT Raw View
Ron Natalie wrote:
> Setjmp/longjmp has long been an implementation pain in the butt. When
> it was originally implemented on PDP-11's, it was real simple, all you
> had to do was save the stack pointer a couple of other registers and
> restore them. ...
Actually it's still that simple, on nearly every platform
including the PDP-11. 6th Edition Unix had similar
functions called setexit/reset, and I recall seeing
several revisions of these in the user community, some of
which used stack unwinding.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Thu, 2 Dec 2004 18:22:01 GMT Raw View
Ron Natalie wrote:
> Max T. Woodbury wrote:
>
>> That is correct for C++ exceptions. It does not exist for
>> setjmp/longjmp.
>> setjmp/longjmp need to be augmented in a way that will not break extant
>> code. Do you have any suggestions on how to do that?
>>
> The point I was trying to make is that C++ has no need for setjmp/longjmp.
> If we were going to extend C and C++, it would be better to fix C to have
> a reasonable exception strategy rather than the rather adhoc codification
> of setjmp/longjmp library functions.
That would be very nice if it can be done without turning C into C++. I get
the impression that you need polymorphism to do exceptions properly and that
'aint gona happen' to C.
On the other hand, fixing the resource leakage problem associated with
setjmp/longjmp should be informed by the solution that C++ has for the
exception problem. Further, where there is a mixed C/C++ environment, the
two should work together. Both communities will have useful things to say
on the subject, thus the cross-posting.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Dan.Pop@cern.ch (Dan Pop)
Date: Fri, 3 Dec 2004 02:54:41 GMT Raw View
In <41ade851$0$1614$9a6e19ea@news.newshosting.com> ron@sensor.com (Ron Natalie) writes:
>The point I was trying to make is that C++ has no need for setjmp/longjmp.
Entirely agreed.
>If we were going to extend C and C++, it would be better to fix C to have
>a reasonable exception strategy rather than the rather adhoc codification
>of setjmp/longjmp library functions.
C, as the low level programming language it is, has no need for *any*
exception mechanism. People needing a reasonable exception mechanism
know where to find C++.
Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Dan.Pop@ifh.de
Currently looking for a job in the European Union
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: DAGwyn@null.net ("Douglas A. Gwyn")
Date: Fri, 3 Dec 2004 07:02:50 GMT Raw View
Dan Pop wrote:
> C, as the low level programming language it is, has no need for *any*
> exception mechanism.
I take exception to that.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Fri, 3 Dec 2004 07:02:46 GMT Raw View
Ron Natalie wrote:
> I don't know WHERE you got that assumption. C++ exceptions work just
> fine without polymorphism, but you can use that if you like. If you wanted
> to do it in C, you could limit the throw/catch types to int (which is
> really all longjmp supports anyhow).
There are multiple kinds of exceptions all derived from the same basic type.
I believe that is polymorphism. You might be able to create A type of exception
without polymorphism, but you could not create multiple types of exceptionS without
it.
Bob Bell wrote:
> max.teneyck.woodbury@verizon.net ("Max T. Woodbury") wrote in message news:<E3Frd.16595$%C6.607@trnddc02>...
>
>>That would be very nice if it can be done without turning C into C++. I get
>>the impression that you need polymorphism to do exceptions properly and that
>>'aint gona happen' to C.
>
> Not true; exceptions and polymorphism are orthogonal. There is no
> reason why an exception mechanism couldn't be centered around a
> system-defined struct, or even int.
To do catch or try you need something like a jmp_buf. That eliminates
anything as simple as an int from consideration. As I mentioned above
there is a connection between exceptions polymorphism.
>>On the other hand, fixing the resource leakage problem associated with
>>setjmp/longjmp should be informed by the solution that C++ has for the
>>exception problem. Further, where there is a mixed C/C++ environment, the
>>two should work together. Both communities will have useful things to say
>>on the subject, thus the cross-posting.
>
>
> There are two ways to release resources during exception handling in
> C++:
>
> -- write a try/catch to interrupt the exception, release the resource
> and rethrow
> -- use the destructor of an object on the stack to release the
> resource (RAII)
>
> The first can be simulated quite easily in C using setjmp/longjmp,
> especially if the exception is restricted to a single type.
>
> I don't see any reasonable way to simulate the second in C because
> there is no notion of constructors and destructors. Unfortunately, the
> second approach is widely regarded as vastly superior to the first,
> because it's far less error-prone.
>
> Further, setjmp/longjmp isn't constrained to jump "up the stack" -- it
> could jump to some location that is completely unrelated to a call
> site that led to the current function. For example, it could jump to
> some other location within the current function; what does it mean to
> release resources in this case?
Where did you get THAT from? The only way to set up a jmp_buf is to use
setjmp and that buffer is invalidated when the routine that called setjmp
exits. longjmp is DEFINITELY constrained to only jump "up the stack".
> It seems to me that trying to get setjmp/longjmp to behave like C++
> exceptions is a bit like trying to fit a square peg into a round hole.
> IMHO, the best thing to do is design a new mechanism.
Even with a new mechanism there would still be the problem retrofitting
the setjmp/longjmp mechanism.
Back to your comments on mechanism:
I agree catch/rethrow is a Kluge. There is much more hope on the
destructor front.
It would be possible to register unwind handlers that would be triggered
by the stack level change that longjmp performs. Those handlers could act
as destructors for automatic objects or they could perform other resource
management functions like fclose or free. That registration could even
be done semi-automatically through alternate interfaces. For example
a 'safe fopen' might be named sfopen. The support for this would have to
go beyond providing a registration mechanism. The resource release
functions would have to include a check to see if the resource was
registered and remove the registration when the resource was deallocted.
In a mixed environment, longjmp and exceptions would share much of the
same mechanism. The registration of unwind handlers might even prove
to be a cleaner alternative interface than the catch/rethrow mechanism
in C++.
None of this is new. VMS did unwind in the 80s and IIRCC PLI did it in the
60s.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Fri, 3 Dec 2004 05:19:16 GMT Raw View
Max T. Woodbury wrote:
> That would be very nice if it can be done without turning C into C++.
I never advocated that. I just figured actual language support for non-local
jumps would be better than the hokie "pseudo-library" functions of setjmp.
> I
> get
> the impression that you need polymorphism to do exceptions properly and
> that
> 'aint gona happen' to C.
I don't know WHERE you got that assumption. C++ exceptions work just
fine without polymorphism, but you can use that if you like. If you wanted
to do it in C, you could limit the throw/catch types to int (which is
really all longjmp supports anyhow).
try {
..
throw 3;
} catch(int x) {
...
}
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: DAGwyn@null.net ("Douglas A. Gwyn")
Date: Fri, 3 Dec 2004 07:02:46 GMT Raw View
Ron Natalie wrote:
> to do it in C, you could limit the throw/catch types to int ...
The problem then is in assigning exception codes
across the entire program, which might include
libraries etc. The main variation among C
implementations of exceptions based on longjmp
is in the slickness with which they address that.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Fri, 3 Dec 2004 05:20:05 GMT Raw View
max.teneyck.woodbury@verizon.net ("Max T. Woodbury") wrote in message news:<E3Frd.16595$%C6.607@trnddc02>...
> Ron Natalie wrote:
> > Max T. Woodbury wrote:
> >
> >> That is correct for C++ exceptions. It does not exist for
> >> setjmp/longjmp.
> >> setjmp/longjmp need to be augmented in a way that will not break extant
> >> code. Do you have any suggestions on how to do that?
> >>
> > The point I was trying to make is that C++ has no need for setjmp/longjmp.
> > If we were going to extend C and C++, it would be better to fix C to have
> > a reasonable exception strategy rather than the rather adhoc codification
> > of setjmp/longjmp library functions.
>
> That would be very nice if it can be done without turning C into C++. I get
> the impression that you need polymorphism to do exceptions properly and that
> 'aint gona happen' to C.
Not true; exceptions and polymorphism are orthogonal. There is no
reason why an exception mechanism couldn't be centered around a
system-defined struct, or even int.
> On the other hand, fixing the resource leakage problem associated with
> setjmp/longjmp should be informed by the solution that C++ has for the
> exception problem. Further, where there is a mixed C/C++ environment, the
> two should work together. Both communities will have useful things to say
> on the subject, thus the cross-posting.
There are two ways to release resources during exception handling in
C++:
-- write a try/catch to interrupt the exception, release the resource
and rethrow
-- use the destructor of an object on the stack to release the
resource (RAII)
The first can be simulated quite easily in C using setjmp/longjmp,
especially if the exception is restricted to a single type.
I don't see any reasonable way to simulate the second in C because
there is no notion of constructors and destructors. Unfortunately, the
second approach is widely regarded as vastly superior to the first,
because it's far less error-prone.
Further, setjmp/longjmp isn't constrained to jump "up the stack" -- it
could jump to some location that is completely unrelated to a call
site that led to the current function. For example, it could jump to
some other location within the current function; what does it mean to
release resources in this case?
It seems to me that trying to get setjmp/longjmp to behave like C++
exceptions is a bit like trying to fit a square peg into a round hole.
IMHO, the best thing to do is design a new mechanism.
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: DAGwyn@null.net ("Douglas A. Gwyn")
Date: Fri, 3 Dec 2004 17:45:19 GMT Raw View
Max T. Woodbury wrote:
> there is a connection between exceptions polymorphism.
Execption handling doesn't have to be tied into the
type system.
> Where did you get THAT from? The only way to set up a jmp_buf is to use
> setjmp and that buffer is invalidated when the routine that called setjmp
> exits. longjmp is DEFINITELY constrained to only jump "up the stack".
You don't seem to have understood his point. The
jump can also occur at the same stack level.
> Even with a new mechanism there would still be the problem retrofitting
> the setjmp/longjmp mechanism.
No. The spec for setjmp/longjmp is what it needs
to be, and doesn't have to tie into any separate
exception handling scheme.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Fri, 3 Dec 2004 22:16:34 GMT Raw View
max.teneyck.woodbury@verizon.net ("Max T. Woodbury") wrote in message news:<CMTrd.9970$1z5.7785@trnddc06>...
> Ron Natalie wrote:
> > I don't know WHERE you got that assumption. C++ exceptions work just
> > fine without polymorphism, but you can use that if you like. If you wanted
> > to do it in C, you could limit the throw/catch types to int (which is
> > really all longjmp supports anyhow).
>
> There are multiple kinds of exceptions all derived from the same basic type.
> I believe that is polymorphism. You might be able to create A type of exception
> without polymorphism, but you could not create multiple types of exceptionS without
> it.
Nothing about exception handling per se demands multiple types of
exceptions. It's perfectly fine for there to be a single exception
type, with multiple possible values of that type thrown.
> Bob Bell wrote:
> > max.teneyck.woodbury@verizon.net ("Max T. Woodbury") wrote in message news:<E3Frd.16595$%C6.607@trnddc02>...
> >
> >>That would be very nice if it can be done without turning C into C++. I get
> >>the impression that you need polymorphism to do exceptions properly and that
> >>'aint gona happen' to C.
> >
> > Not true; exceptions and polymorphism are orthogonal. There is no
> > reason why an exception mechanism couldn't be centered around a
> > system-defined struct, or even int.
>
> To do catch or try you need something like a jmp_buf. That eliminates
> anything as simple as an int from consideration.
// C++:
void F(void)
{
try {
throw 0;
}
catch (int x) {
}
}
> As I mentioned above
> there is a connection between exceptions polymorphism.
There's no polymorphism in the previous example, but it is exception
handling. There is no connection between polymorphism and exception
handling; you can have either one without the other. As far as I can
tell, getting stuck on this point simply makes it more difficult to
add some kind of exception mechanism to C, since C has no
polymorphism.
> > Further, setjmp/longjmp isn't constrained to jump "up the stack" -- it
> > could jump to some location that is completely unrelated to a call
> > site that led to the current function. For example, it could jump to
> > some other location within the current function; what does it mean to
> > release resources in this case?
>
> Where did you get THAT from? The only way to set up a jmp_buf is to use
> setjmp and that buffer is invalidated when the routine that called setjmp
> exits. longjmp is DEFINITELY constrained to only jump "up the stack".
void F(void)
{
jmp_buf buf;
setjmp(buf);
/* ... */
longjmp(buf, 1);
}
This is not a jump "up the stack". The only constraint on longjmp is
that the jmp_buf must have been initialized by a previous call to
setjmp; it doesn't matter whether that occurs at a higher nesting
level or in a caller.
void F(void)
{
jmp_buf buf;
if (/* ... */)
while (/* ... */ ) {
for (/* ... */) {
setjmp(buf);
}
}
if (/* ... */)
while (/* ... */ ) {
for (/* ... */) {
longjmp(buf);
}
}
}
Again, what does it mean to release resources in this case?
By returning a jmp_buf from a function, it is even possible to do
horrible things like jumping into a called function after that
function has returned.
> > It seems to me that trying to get setjmp/longjmp to behave like C++
> > exceptions is a bit like trying to fit a square peg into a round hole.
> > IMHO, the best thing to do is design a new mechanism.
>
> Even with a new mechanism there would still be the problem retrofitting
> the setjmp/longjmp mechanism.
>
> Back to your comments on mechanism:
>
> I agree catch/rethrow is a Kluge. There is much more hope on the
> destructor front.
>
> It would be possible to register unwind handlers that would be triggered
> by the stack level change that longjmp performs.
Longjmp doesn't necessarily perform a stack level change, as shown in
my previous examples.
> Those handlers could act
> as destructors for automatic objects or they could perform other resource
> management functions like fclose or free. That registration could even
> be done semi-automatically through alternate interfaces. For example
> a 'safe fopen' might be named sfopen.
void F(void)
{
jmp_buf buf;
if (/* ... */) {
FILE* fp=sfopen("foo", "r");
while (/* ... */ ) {
for (/* ... */) {
setjmp(buf);
fprintf(fp, "Hello, world.\n");
}
}
fclose(fp);
}
longjmp(buf);
}
What would you expect the fprintf to do after getting there via the
longjmp?
> The support for this would have to
> go beyond providing a registration mechanism. The resource release
> functions would have to include a check to see if the resource was
> registered and remove the registration when the resource was deallocted.
I don't see any other way to do it in C other than some kind of system
like the one you describe here. However, I'm convinced that
overloading setjmp/longjmp to do this is entirely the wrong approach,
because it's too powerful; it allows jumps that are nonsensical from
the point of view of exception handling.
A new facility is a much better idea.
The programmer needs to be able to describe an "exception context",
which is a group of "try" statements together with a group of
"exceptional" statements. If an exception is thrown while executing
the "try" statements, control transfers to the "exceptional"
statements, passing along an indication of what the exception was.
Implementing this much using setjmp and longjmp is not difficult, and
gets us as far as the try/catch approach to resource release.
For automatic resource release, we need some mechanism to tell the
system, when execution transfers from inside the "try" statements to
the "exception" statements, to execute a "release" function for every
resource allocated in the "try" statements. I can only see this
happening in C using some kind of registration facility, but rather
than providing an alternative to existing functions like "sfopen", I'd
rather see a single function that looks like this:
void register_resource(void* resource, void (*release)(void*));
This registers a resource and the function that releases it with the
current try context; whenever control exits the try context it
executes the release function, whether control exits due to normal
execution or because an exception is thrown. Example:
FILE* fp = fopen("foo", "r");
register_resource(fp, &fclose);
This can all be implemented today in C as a series of macros. What
can't be implemented today, and would require a change to the
language, is getting return statements to honor the release functions,
so that executing a return from the middle of a try context will
execute the registered release functions.
> In a mixed environment, longjmp and exceptions would share much of the
> same mechanism.
Modern implementations of C++ exception handling do not use the kind
of run-time registration discussed in this post; such an
implementation would be a huge step backwards.
> The registration of unwind handlers might even prove
> to be a cleaner alternative interface than the catch/rethrow mechanism
> in C++.
If you're suggesting that C++ programmers should use the
register_resource function (or whatever the mechanism is), that also
would be a big step backwards, IMO.
void F()
{
std::auto_ptr<Foo> p(new Foo());
// ...
}
vs.
void DeleteFoo(Foo* iFoo)
{
delete iFoo;
}
void F()
{
Foo* p(new Foo());
register_release(p, DeleteFoo);
// ...
}
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: christian.bau@cbau.freeserve.co.uk (Christian Bau)
Date: Sat, 4 Dec 2004 00:33:22 GMT Raw View
In article <c87c1cfb.0412031243.288af744@posting.google.com>,
belvis@pacbell.net (Bob Bell) wrote:
> By returning a jmp_buf from a function, it is even possible to do
> horrible things like jumping into a called function after that
> function has returned.
Good luck with that. In theory, it is undefined behaviour. In practice,
it will crash.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Sat, 4 Dec 2004 00:33:08 GMT Raw View
Douglas A. Gwyn wrote:
> Max T. Woodbury wrote:
>
>> there is a connection between exceptions polymorphism.
>
> Execption handling doesn't have to be tied into the
> type system.
Could you explain that. I believe that you will need an object
of some form to communicate the information about an exception to
throw/catch/try et al. An object has a type connected to it.
>> Where did you get THAT from? The only way to set up a jmp_buf is to use
>> setjmp and that buffer is invalidated when the routine that called setjmp
>> exits. longjmp is DEFINITELY constrained to only jump "up the stack".
>
> You don't seem to have understood his point. The
> jump can also occur at the same stack level.
The "up the stack" is in quotes because it was the phrase used by Bob Bell.
He was claiming you could longjmp off the stack. You snipped the phrase "it
could jump to some location that is completely unrelated to a call
site that led to the current function" which is simply wrong. I can see a
quibble about what constitutes "up the stack" but it ignores the fact that
there has to be a segment of stack context that will be resorted to by the
process implemented by longjmp and that segment will indeed be "up the stack".
Further, the jump point has to be to a point where a setjmp call occurred in the
routine with "a call site that led to the current function" that had to be executed
before that call and is therefore "related" to that call site even if it is not the
call site itself. The only possible point here is that there may not be a need to
unwind the stack in some cases and there will be cases where no resource leakage
can occur. The problem being addressed is how to handle resource leakage when it
does occur.
>> Even with a new mechanism there would still be the problem retrofitting
>> the setjmp/longjmp mechanism.
>
> No. The spec for setjmp/longjmp is what it needs
> to be, and doesn't have to tie into any separate
> exception handling scheme.
The setjmp/longjmp specification is the minimum that was acceptable in 1986 when
the C standard was first contemplated. It could have been extended by the C++
standard when C++ added exceptions but it was not. It would not have been
impossible to do what the POSIX standard did to other parts of C and extend the
setjmp/longjmp specification in a way that was compatible with the C standard, but
that would probably have raised issues about the boundary between the two languages.
That is the "need" you are talking about is a political "need" and ignores the
technical needs of at least some of the programming community.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Sat, 4 Dec 2004 05:25:50 GMT Raw View
Max T. Woodbury wrote:
> Douglas A. Gwyn wrote:
>
>> Execption handling doesn't have to be tied into the
>> type system.
>
>
> Could you explain that. I believe that you will need an object
> of some form to communicate the information about an exception to
> throw/catch/try et al. An object has a type connected to it.
Yes, but right now C++'s longjmp mechanism only passes an integer (and
even that it doesn't do completely). So, you can assume the type is
int if you wanted to replace that directly with some exception-like
system.
>
> The "up the stack" is in quotes because it was the phrase used by Bob Bell.
> He was claiming you could longjmp off the stack. You snipped the phrase
> "it
> could jump to some location that is completely unrelated to a call
> site that led to the current function" which is simply wrong.
The issue is that longjmp can go back to any place within the same
function. C++ exceptions can't escape the try block. For example:
void foo() {
{
setjmp(&jmpbuf) ;
}
//...
{
longjmp(&jmpbuf);
}
}
is quite possible...the only restriction is that the function can not have
returned (but you may have exitted the block that has the setjmp. C++
try/throw however ENFORCES structure. You must have a direct path to
the catch block. This is not a bad thing in my opinion.
> The setjmp/longjmp specification is the minimum that was acceptable in
> 1986 when
> the C standard was first contemplated.
No it can not safely be done. Imagine again:
void foo() {
{
SomeType o;
setjmp(&jmpbuf);
o.function();
}
{
longjmp(&jmpbuf);
}
}
In the first block he object o is created and destroyed. The longjmp will send
conrol back into the middle of the block. What is going to happen to that variable?
The object o will be destroyed after the first block exis
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Sat, 4 Dec 2004 21:38:18 GMT Raw View
christian.bau@cbau.freeserve.co.uk (Christian Bau) wrote in message news:<christian.bau-ED669A.00224904122004@slb-newsm1.svr.pol.co.uk>...
> In article <c87c1cfb.0412031243.288af744@posting.google.com>,
> belvis@pacbell.net (Bob Bell) wrote:
>
> > By returning a jmp_buf from a function, it is even possible to do
> > horrible things like jumping into a called function after that
> > function has returned.
>
> Good luck with that. In theory, it is undefined behaviour. In practice,
> it will crash.
Of course; I wasn't suggesting that it was a good idea. Note the use
of the word "horrible." ;-)
The point was that the semantics of exception throwing (transfer
control to an enclosing scope) do not match the semantics of
setjmp/longjmp (transfer control to any location at which setjmp was
called).
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kst-u@mib.org (Keith Thompson)
Date: Sat, 4 Dec 2004 21:38:17 GMT Raw View
max.teneyck.woodbury@verizon.net ("Max T. Woodbury") writes:
> Douglas A. Gwyn wrote:
>> Max T. Woodbury wrote:
>>
>>> there is a connection between exceptions polymorphism.
>>
>> Execption handling doesn't have to be tied into the
>> type system.
>
> Could you explain that. I believe that you will need an object
> of some form to communicate the information about an exception to
> throw/catch/try et al. An object has a type connected to it.
Consider the Ada exception system. An exception in Ada is not an
object; it has a name, but no type. For example:
with Text_IO; use Text_IO;
procedure Foo is
Number_Is_Odd : exception;
procedure Expect_Even(Num: Integer) is
begin
if Num mod 2 /= 0 then
raise Number_Is_Odd;
else
Put_Line("ok");
end if;
end Expect_Even;
begin
for I in 0 .. 1 loop
begin
Put_Line("Calling Expect_Even(" & Integer'Image(I) & ")");
Expect_Even(I);
exception
when Number_Is_Odd =>
Put_Line("Oops, number is odd");
end;
end loop;
end Foo;
This is Ada 83. Ada 95 adds some facilities for associating
information (strings) with exception occurrences.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net (James Kuyper)
Date: Sat, 4 Dec 2004 21:38:46 GMT Raw View
belvis@pacbell.net (Bob Bell) wrote in message news:<c87c1cfb.0412031243.288af744@posting.google.com>...
..
> By returning a jmp_buf from a function, it is even possible to do
> horrible things like jumping into a called function after that
> function has returned.
How can you do that? 7.13.2.1: "... if the function containing the
invocation of the setjmp macro has terminated execution ... the
behavior [of longjmp] is undefined."
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Wed, 8 Dec 2004 22:35:44 GMT Raw View
Bob Bell wrote:
> "Max T. Woodbury" wrote:
>> Bob Bell wrote:
>>> "Max T. Woodbury"
>
> So perhaps the problem here is that it wasn't clear what I meant by "up
> the stack." I meant "to an enclosing scope". This could mean
> transferring control to a caller, or it could be an enclosing scope in
> the current function. Without limiting the transfer of control in this
> way, it's hard to imagine how resources can be cleaned up reliably.
It's the same problem that exists with 'goto'. The title of the section
that defines setjmp/longjmp says something about 'non-local goto'.
>> I am well aware the longjmp does not always unwind the stack. The problem
>> is that it should be ABLE to do something about resource leakage WHEN it
>> does.
>
> You want longjmp to somehow be able to tell when it can release
> resources and when it can't? How do you propose it determine that?
> Supposing this problem is overcome, what would you like longjmp to do
> when it can't release resources? Specifically, what should happen if
> the programmer thinks one thing, but longjmp is actually doing
> something else? How will the programmer know?
How does the C++ exception handler do it? Use the same mechanism.
> Is this kind of complexity and fragility really better than a new
> mechanism that could be designed to ALWAYS transfer control
> appropriately?
Argh! It's not all that complicated. As for 'fragile', using the
extant C++ exception mechanism will clean up a number of cases that
are currently broken.
>> What is missing is a way to specify that some resources
>> will need to be released if the stack is unwound in C. It would be
>> helpful if you would think about that problem rather than dragging
>> in irrelevant side issues.
>
> The issue is whether setjmp/longjmp are appropriate for releasing
> resources. I claim they aren't, and my reasons aren't "side issues."
Trying to define an exception handling mechanism for C is the side
issue I'm trying to avoid. It's just not ready for prime time now.
On the other hand both setjmp/longjmp and C++ exceptions have to unwind
the stack. You say they are different problems and must be treated
differently. I don't see any justification for separating the two.
>>> void F(void)
>>> {
>>> jmp_buf buf;
>>>
>>> if (/* ... */) {
>>> FILE* fp=sfopen("foo", "r");
>>>
>>> while (/* ... */ ) {
>>> for (/* ... */) {
>>> setjmp(buf);
>>> fprintf(fp, "Hello, world.\n");
>>> }
>>> }
>>> fclose(fp);
>>> }
>>>
>>> longjmp(buf);
>>> }
>>>
>>> What would you expect the fprintf to do after getting there via the
>>> longjmp?
>>
>> Return EOF because fp does not point to an open file or stream.
>
> I think you missed the point: sfopen (and other such "safe" calls) will
> never be safe as long as the programmer can jump past them.
You're putting a different meaning on 'safe'. You're using it in the sense
'it prevent someone from doing something wrong' while I'm using it in the
sense 'it gets cleaned up properly'.
The main problem with the code cited is that it intended to show that it
is possible to willfully screw up. You can do that any of a number of ways
without using setjmp/longjmp. What is being ignored is how it could be
used constructively:
void F( jmp_buf * on_error) // or as a global...
{
...
if ( .../*Is it FUBAR?*/ )
longjmp(on_error,1);
...
}
void G( jmp_buf * on_error)
{
FILE * f;
...
f = sfopen(...);
fprintf( f, ...);
F( on_error);
fprintf( f, ...);
fclose( f);
}
int main( void)
{
jmp_buf on_error;
if ( 0 == setjmp( on_error) ) {
// Try block
G(on_error);
} else {
// Retry block
...
}
}
If condition FUBAR arises, f would be closed as part of the unwind. Without
an sfopen, you can't get at f to close it without exposing f as a global or
mucking up the interface to G.
>>>> The support for this would have to
>>>> go beyond providing a registration mechanism. The resource release
>>>> functions would have to include a check to see if the resource was
>>>> registered and remove the registration when the resource was deallocted.
>>>
>>> I don't see any other way to do it in C other than some kind of system
>>> like the one you describe here. However, I'm convinced that
>>> overloading setjmp/longjmp to do this is entirely the wrong approach,
>>> because it's too powerful; it allows jumps that are nonsensical from
>>> the point of view of exception handling.
>>
>> Would you please NOT use swear words like "nonsensical". C and C++
>> both contain 'goto' because there are occasions when "sensible"
>> logical structures are not up to the job of handling unusual conditions.
>> (In many cases you can remove the 'goto' but the resulting code is
>> harder to understand and less efficient than the code with the 'goto'.
>> It also true that lots of 'goto's is a sign of poor understanding and
>> a lack of forethought. Knowing when to use a 'goto' and when not to is
>> part of the ART of programming.) setjmp/longjmp is just a bigger 'goto'.
>> Of course it can be abused. That is the nature of this particular kind
>> of 'beast'. The fact that you think something is "too powerful" to be
>> included in the language and expect that argument to be accepted
>> indicates to me that you are presenting emotional arguments rather than
>> rational ones. Will you please stop that.
>
> You seem to be misunderstanding almost every point I'm making. I didn't
> say that anything is too powerful to be included in the language; I
> said that setjmp and longjmp are too powerful to implement the behavior
> you're after. In order to perform some kind of stack walkback and
> release resources, you need a facility that walks up the stack. Longjmp
> is inappropriate because it doesn't do that; it can jump to any
> previously executed setjmp call, whether that corresponds to a point
> which makes sense for resource release or not.
Sorry, no. You don't have to walk the stack. You have to walk a linked
list of resources allocated on the stack or resources that need to be
released if the stack level drops below some trigger level. A jmp_buf
has to include the target stack level. Before actually changing the
stack level, follow the resource chain and release the specified
resources until you get to a resource that should not be released.
Then do your usual longjmp stuff.
>>> The programmer needs to be able to describe an "exception context",
>>> which is a group of "try" statements together with a group of
>>> "exceptional" statements. If an exception is thrown while executing
>>> the "try" statements, control transfers to the "exceptional"
>>> statements, passing along an indication of what the exception was.
>>
>> And if the the exception paradyme it not appropriate for the environment
>> are you going to force it on the programmer?
>
> I'm not forcing anything on anyone, just tossing out ideas. It seems to
> me that if the programmer wants the stack unwound in order to release
> resources, he's got to tell the system where he wants it unwound to,
> what he wants done during unwinding, and when it should occur.
The stop level of the unwind is in the jmp_buf. When it should be unwound
is on entry to longjmp. What to do during the unwind is part of what has
to be hashed out. It should include any normal C++ deconstructors and such
additional routines as the programmer specifies. That is basically the same
process as unwinding the stack in a C++ exception. For consistency, the
additional routines the programmer asks to be called should be called by
both a setjmp/longjmp unwind and an exception unwind.
>>>> In a mixed environment, longjmp and exceptions would share much of the
>>>> same mechanism.
>>>
>>> Modern implementations of C++ exception handling do not use the kind
>>> of run-time registration discussed in this post; such an
>>> implementation would be a huge step backwards.
>>
>> Ah! You speak as though an authority on the subject. I would hear
>> your wisdom so I can judge for myself. Though I have more than a little
>> knowledge of how this works, I would like to hear other opinions on how
>> and more importantly WHY things are the way they are. PLEASE elaborate!
>> (That sounds much too sarcastic. Please forgive me on that. I really
>> am interested in any practical information you can provide.)
>
> Consider this function:
>
> void F()
> {
> Foo f;
> Bar b;
>
> // ...
> }
>
> If the function throws an exception, and that exception passes up
> through F(), the f and b objects must be destroyed by having their
> destructors executed. This can be accomplished by creating a table
> indexed by program counter that describes the cleanup actions that
> should be taken if an exception is thrown from any particular point in
> the function. Here's F() again with comments signficant points in the
> function followed by a corresponding exception table:
>
> void F()
> {
> // 1
>
> Foo f;
>
> // 2
>
> Bar b;
>
> // 3
>
> // ...
> }
>
> PC Section Walkback Actions
> ------------------------------
> 1 nothing
> 2 destroy f
> 3 destroy f and b
>
> No matter how complex a function is, such a table can always be
> determined at compile time. The main advantage of this approach is that
> it adds no runtime overhead when an exception is not thrown. In
> particular, no registration of the destruction functions is needed --
> the Foo constructor runs to construct f, then the Bar constructor runs
> to construct b, then the rest of the function runs.
>
> If an exception is thrown somewhere, then as control passes up through
> F(), the point inside F() through which the exception passes is looked
> up in the table to see what needs to be done. Suppose an exception is
> thrown while constructing f; control is in section 1, so according to
> the table, nothing needs to be done. If an exception is thrown while
> constructing b, however, control is in section 2, so f must be
> destroyed.
So you're saying the exception handler has an intimate knowledge of the
stacks structure and has a table of things to do when an exception occurs.
As usual in C++ the linker has an incestuous knowledge of the language... :-}
1) Have longjmp call the exception unwind code you described before munging
the stack. (It may even be that that code does the munging and longjmp
will not have to worry about it any longer.)
2) Prefix that code with a check of the registration list. This does NOT
require that the other more efficient mechanism be discarded. It just
allows things that the normal mechanism can't handle to be taken care
of. If the list is empty, the overhead will be small. You'll only
pay for the mechanism if you use it.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: sjhoweATdialDOTpipexDOTcom@eu.uu.net ("Stephen Howe")
Date: Thu, 9 Dec 2004 05:29:59 GMT Raw View
>> You want longjmp to somehow be able to tell when it can release
>> resources and when it can't? How do you propose it determine that?
>> Supposing this problem is overcome, what would you like longjmp to do
>> when it can't release resources? Specifically, what should happen if
>> the programmer thinks one thing, but longjmp is actually doing
>> something else? How will the programmer know?
>
> How does the C++ exception handler do it? Use the same mechanism.
How?
In C++, if you have a file represented by fstream, ifstream or ofstream, as
an exception is being thrown and looking for the catch handler, the
destructors of these objects will close any open file.
All well and good.
In C, if you have opened a file using fopen(), how will the exception being
thrown know to call fclose() ???
A pointer to FILE is just a dumb pointer, not an object unlike C++ streams.
Stephen Howe
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: belvis@pacbell.net (Bob Bell)
Date: Thu, 9 Dec 2004 07:01:52 GMT Raw View
"Max T. Woodbury" wrote:
> Bob Bell wrote:
> > "Max T. Woodbury" wrote:
> >> I am well aware the longjmp does not always unwind the stack. The problem
> >> is that it should be ABLE to do something about resource leakage WHEN it
> >> does.
> >
> > You want longjmp to somehow be able to tell when it can release
> > resources and when it can't? How do you propose it determine that?
> > Supposing this problem is overcome, what would you like longjmp to do
> > when it can't release resources? Specifically, what should happen if
> > the programmer thinks one thing, but longjmp is actually doing
> > something else? How will the programmer know?
>
> How does the C++ exception handler do it?
OK, I'll tell you how those questions are answered by the C++ exception
handling mechanism:
Q. When can it release resources and when can't it?
A. It can always release (i.e., it always executes destructors of
objects on the stack).
Q. What does it do when it can't release resources?
A. N/A, it always releases.
Q. What happens when the programmer thinks one thing but it actually
does something else?
A. N/A, it always releases.
> Use the same mechanism.
The C++ mechanism works because the transfer of control is constrained
to be towards an enclosing scope. It is impossible to throw a C++
exception across scopes or down into a contained scope, so these issues
don't come up.
So again, how will longjmp determine when it can release resources and
when it can't? What will it do when it can't release? What will happen
if someone longjmps from insider a resource release function that was
triggered by a longjmp?
Look, the point is really simple: if you seriously expect anyone to
consider your idea, you've got to describe how it's going to behave. How
do you expect this to be implemented? What will the implementation do in
_all_ cases, not just the few cases you think are useful? You believe
that longjmp can be made to work this way, so tell us how. I think we
need to see more detail than "just do what C++ does."
Bob
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: DAGwyn@null.net ("Douglas A. Gwyn")
Date: Thu, 9 Dec 2004 21:04:14 GMT Raw View
David Abrahams wrote:
> For that, you need to change the 'C' standard, not the C++ one.
No, the C standard has no way to talk about C++ exceptions.
The specification needs to be in the document that knows
about the facility.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kst-u@mib.org (Keith Thompson)
Date: Fri, 10 Dec 2004 05:25:19 GMT Raw View
DAGwyn@null.net ("Douglas A. Gwyn") writes:
> David Abrahams wrote:
>> For that, you need to change the 'C' standard, not the C++ one.
>
> No, the C standard has no way to talk about C++ exceptions.
> The specification needs to be in the document that knows
> about the facility.
The context was John Nagle writing:
] Agreed. There should at least be defined behavior
] when exception unwinding ends up in C code.
] At least, a call to Terminate.
I don't believe it would be possible for the C++ standard to mandate
the behavior of C code in the presence of C++ exceptions, at least not
without some cooperation from the C standard. (I think we're talking
about actual C code, not C-like code within C++; C++ defines an
interface to C with the 'extern "C"' construct.)
To have defined behavior when a C++ exception propagates to C code,
the C standard would have to be extended enough so that it *can* talk
about C++ exceptions. It's not impossible, but it's extremely
unlikely.
Conceivably the C++ standard could constrain the implementation of
exceptions to something that C code (via extern "C") could handle.
I suspect that's unlikely as well, but I don't know as much about
C++ as I do about C.
Of course an implementation (which may include integrated C and C++
compilers) can do whatever it likes in this area by choosing to define
behavior that's left undefined by the standard(s).
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dave@boost-consulting.com (David Abrahams)
Date: Fri, 10 Dec 2004 05:25:32 GMT Raw View
Douglas A. Gwyn wrote:
> David Abrahams wrote:
>> For that, you need to change the 'C' standard, not the C++ one.
>
> No, the C standard has no way to talk about C++ exceptions.
Sure it does.
> The specification needs to be in the document that knows
> about the facility.
The C++ standard has absolutely no way to make requirements on the 'C'
language. If you want to standardize the idea that 'C' compilers should
generate code that can deal with C++ exceptions passing through it, you
had better put it where the requirements on 'C' compilers are documented.
In truth, this is a much bigger issue than any one language standard can
handle: you need an ABI standard like
http://www.codesourcery.com/cxx-abi/abi.html that integrates the basic
mechanism for exception handling into the platform.
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: max.teneyck.woodbury@verizon.net ("Max T. Woodbury")
Date: Sun, 12 Dec 2004 23:59:57 GMT Raw View
Ron Natalie wrote:
> I should point out that I would consider getting requiring
> C++ exceptions to propagate with predictable behavior through
> C functions in the call stack to be of a higher importance
> than reforming setjmp/longjmp.
Unless there is a way to invoke something like a 'C++ exception
propagation' in C, there is no reason for the C language
specification to be modified to include this property.
Further, any such change will have to have a minimal impact on
extant code. That means the C LANGUAGE can not be changed to do
this kind of thing. Any such changes will have to take the form
of ADDITIONS to the library specification.
(I could be wrong about this. It might be possible to add a
type qualifier like const or volatile that has resource
management implications much the way complex was added.)
So adding a resource release mechanism to setjmp/longjmp is a
necessary flip side to getting C to handle C++ exceptions properly.
max@mtew.isa-geek.net
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]