Austin Group Defect Tracker

Aardvark Mark III


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000516 [1003.1(2008)/Issue 7] System Interfaces Objection Omission 2011-11-24 15:45 2019-06-10 08:55
Reporter geoffclare View Status public  
Assigned To ajosey
Priority normal Resolution Accepted As Marked  
Status Closed  
Name Geoff Clare
Organization The Open Group
User Reference
Section longjmp
Page Number 1256
Line Number 41378
Interp Status Approved
Final Accepted Text See Note: 0001198
Summary 0000516: Calling longjmp() from a signal handler
Description The longjmp() page describes the following restriction on calling
longjmp() from a signal handler:

    However, if longjmp() is invoked from a nested signal handler
    (that is, from a function invoked as a result of a signal raised
    during the handling of another signal), the behavior is undefined.

There is another more obvious restriction that should be described but
currently is not (except in rationale, XRAT B.2.4.3 P3515 L118392).

To illustrate the problem, suppose the signal handler was called
during a call to malloc() when its internal data structures were in a
partly-updated state. After the longjmp() call the behaviour of
any subsequent call to malloc(), realloc(), or free() would be
undefined.

Generalising, the restriction is that if longjmp() is called from a
signal handler which interrupted a non-async-signal-safe function,
the behavior of any subsequent call to a non-async-signal-safe
function is undefined. Also, if the process returns from the initial
call to main() this is equivalent to calling exit() (which is a
non-async-signal-safe function) and so the same restriction applies.

In addition, this text near the end of 2.4.3 does not properly account
for [sig]longjmp() and for returning from main():

    ... all functions defined by this volume of POSIX.1-2008 shall
    behave as defined when called from or interrupted by a
    signal-catching function, with a single exception: when a signal
    interrupts an unsafe function and the signal-catching function
    calls an unsafe function, the behavior is undefined.

and likewise for the corresponding rationale.
Desired Action Change:

    However, if longjmp() is invoked from a nested signal handler ...

to:

    However, if longjmp() is invoked from a signal handler which
    interrupted a non-async-signal-safe function or equivalent
    (such as the processing equivalent to exit() performed after
    a return from the initial call to main()), the behavior of any
    subsequent call to a non-async-signal-safe function or equivalent
    is undefined. In addition, if longjmp() is invoked from a nested
    signal handler ...

At page 1256 line 41395 add a new paragraph to APPLICATION USAGE:

    It is recommended that applications do not call longjmp() or
    siglongjmp() from signal handlers. To avoid undefined behavior
    when calling these functions from a signal handler the application
    needs to ensure that the call is not made from a nested signal
    handler and also ensure one of the following two things:

    1. After the call to longjmp() or siglongjmp() the process only
    calls async-signal-safe functions and does not return from the
    initial call to main().

    2. Any signal whose handler calls longjmp() or siglongjmp() is
    blocked during every call to a non-async-signal-safe
    function, and no such calls are made after returning from the
    initial call to main().

At page 490 line 16758 section 2.4.3 change:

    ... with a single exception: when a signal interrupts an unsafe
    function and the signal-catching function calls an unsafe
    function, the behavior is undefined.

to:

    ... with the exception that when a signal interrupts an unsafe
    function or equivalent (such as the processing equivalent to
    exit() performed after a return from the initial call to main())
    and the signal-catching function calls an unsafe function, the
    behavior is undefined. Additional exceptions are specified in
    the descriptions of individual functions such as longjmp().

Cross-volume change to XRAT ...
At page 3515 line 118400 section B.2.4.3 change:

    POSIX.1 does not define the behavior when any unsafe function is
    called in a signal handler that interrupts any unsafe function.

to:

    POSIX.1 does not define the behavior when any unsafe function is
    called in (or after a longjmp() out of) a signal handler that
    interrupts any unsafe function or the non-async-signal-safe
    processing equivalent to exit() that is performed after return
    from the initial call to main().
Tags tc2-2008
Attached Files

- Relationships

-  Notes
(0001053)
Konrad_Schwarz (reporter)
2011-11-25 08:35

I consider this defect report unnecessary.

As [sig]longjmp is not on the list of async-signal-safe functions, the standard does not allow it to be called _without restriction_ from a signal handler.

As with other "unsafe" functions, it is perfectly OK, from the point of view
of the standard, to call [sig]longjmp when it is known that the signal
did not interrupt some other unsafe function.

Of course the _application_ must ensure that _it_ can properly unwind whatever
operation was in progress; but this is always the case when using longjmp,
irrespective of whether it is being called from a signal handler.

I'm not sure why the added text discusses processing from exit: if an atexit handler raises a signal, why can't a signal handler longjmp to a setjmp'd
location in that atexit handler?

The case of an asynchronous signal, such as SIGALRM, jumping back to
somewhere within main, is already handled by longjmp:

  If the function containing the invocation of setjmp() has terminated
  execution in the interim, or if the invocation of setjmp() was within
  the scope of an identifier with variably modified type and execution
  has left that scope in the interim, the behavior is undefined.

System-defined exit processing must not generate any signals, given
a fully conforming application.

In the proposed APPLICATION USAGE, item 1:

   1. After the call to longjmp() or siglongjmp() the process only
    calls async-signal-safe functions and does not return from the
    initial call to main().

is an extension to the current standard: currently siglongjmp()
called from a signal handler interrupting an unsafe function
leads to undefined behavior; this APPLICATION USAGE changes
that. I don't think you want that.

Item 2 of APPLICATION USAGE is one way of ensuring what the standard
already says:

  when a signal interrupts an unsafe function and the signal-catching
  function calls an unsafe function, the behavior is undefined.

However, other ways exist, e.g., for a synchronous exception like SIGSEGV,
passing proper arguments to standard functions ensures they won't generate
the signal. (Passing incorrect arguments is already undefined).

Thus, the phrase "also ensure one of the following two things" is wrong.

I think it would be perfectly acceptable to leave the current, concise wording
on pg. 490:

  when a signal interrupts an unsafe function and the signal-catching
  function calls an unsafe function, the behavior is undefined.

Honestly, I think the proposed wording just muddles the issue. At most,
I would add a note that [sig]longjmp is an unsafe function.

Similarly, the XRAT change. As [sig]longjmp() is an usafe function, it does not
need to be treated specially.
(0001070)
geoffclare (manager)
2011-11-30 15:57

Discussions on the mailing list have identified two additional issues:

1. The restriction on calling longjmp() from a nested signal handler
derives from C90 and is felt not to be necessary on POSIX systems.
We could remove it.

2. Section 2.4.3 conflicts with the longjmp() description. It says,
after the table of async-signal-safe functions:

    All functions not in the above table are considered to be unsafe
    with respect to signals.

Thus all functions are either safe or unsafe; it does not allow for
functions that are "safe but with restrictions". Two possible
solutions are:

A. Modify 2.4.3 so that it allows for functions that are "safe but
with restrictions".

B. Modify the longjmp() description so that it says something like:

    ... longjmp() shall execute correctly in contexts of interrupts,
    signals, and any of their associated functions, provided the
    interrupt did not occur during a call to a non-async-signal-safe
    function.

Option A more closely represents the situation that exists on current
implementations, and I believe it is probably what the standard
originally intended for longjmp().

Option B would greatly restrict the use of longjmp() from signal
handlers, and would, as pointed out in Note: 0001053 (which presupposes
option B), make much of the desired action unnecessary.

Once the group decides which way to go on these two issues, I will
propose a revised set of changes.
(0001195)
geoffclare (manager)
2012-04-11 10:59
edited on: 2012-04-12 09:10

This is a revised proposal following the decision in the 5th April
teleconference to remove the nested signal handler restriction and
to modify 2.4.3 so that it allows longjmp() to be "safe but with
restrictions". (It does the latter without introducing a third
signal safety category, since the nested restriction is removed.
Instead it adds longjmp() and siglongjmp() to the async-signal-safe
list and specifies that although calls to async-signal-safe functions
can be made from signal-catching functions without restriction, for
certain functions there are restrictions on subsequent behaviour.)

At page 1256 line 41377 section longjmp() change:

    As it bypasses the usual function call and return mechanisms,
    longjmp() shall execute correctly in contexts of interrupts,
    signals, and any of their associated functions. However, if
    longjmp() is invoked from a nested signal handler (that is, from
    a function invoked as a result of a signal raised during the
    handling of another signal), the behavior is undefined.

to:

    Although longjmp() is an async-signal-safe function, if it is
    invoked from a signal handler which interrupted a
    non-async-signal-safe function or equivalent (such as the
    processing equivalent to exit() performed after a return from the
    initial call to main()), the behavior of any subsequent call to a
    non-async-signal-safe function or equivalent is undefined.

At page 1256 line 41395 add a new paragraph to APPLICATION USAGE:

    It is recommended that applications do not call longjmp() or
    siglongjmp() from signal handlers. To avoid undefined behavior
    when calling these functions from a signal handler the application
    needs to ensure one of the following two things:

    1. After the call to longjmp() or siglongjmp() the process only
    calls async-signal-safe functions and does not return from the
    initial call to main().

    2. Any signal whose handler calls longjmp() or siglongjmp() is
    blocked during every call to a non-async-signal-safe
    function, and no such calls are made after returning from the
    initial call to main().

At page 489 line 16721 section 2.4.3 change:

    Therefore, applications can invoke them, without restriction, from
    signal-catching functions:

to:

    Therefore, applications can call them, without restriction, from
    signal-catching functions. Note that, although there is no
    restriction on the calls themselves, for certain functions there
    are restrictions on subsequent behavior after the function is
    called from a signal-catching function (see [xref to longjmp()]).

At page 489 line 16722-16755 section 2.4.3 add longjmp() and
siglongjmp() to the table of async-signal-safe functions.

At page 490 line 16758 section 2.4.3 change:

    ... with a single exception: when a signal interrupts an unsafe
    function and the signal-catching function calls an unsafe
    function, the behavior is undefined.

to:

    ... with the exception that when a signal interrupts an unsafe
    function or equivalent (such as the processing equivalent to
    exit() performed after a return from the initial call to main())
    and the signal-catching function calls an unsafe function, the
    behavior is undefined. Additional exceptions are specified in
    the descriptions of individual functions such as longjmp().

Cross-volume change to XBD ...
At page 37 line 1229 section 3.27 change the definition of
Async-Signal-Safe Function from:

    A function that may be invoked, without restriction, from
    signal-catching functions. No function is async-signal-safe unless
    explicitly described as such.

to:

    A function that can be called, without restriction, from
    signal-catching functions. Note that, although there is no
    restriction on the calls themselves, for certain functions there
    are restrictions on subsequent behavior after the function is
    called from a signal-catching function. No function is
    async-signal-safe unless explicitly described as such.

    Note: Async-signal-safety is defined in detail in [xref to XSH
    2.4.3].

Cross-volume changes to XRAT ...

At page 3514 line 118375 section B.2.4.3 change:

    The behavior of unsafe functions, as defined by this section, is
    undefined when they are invoked from signal-catching functions in
    certain circumstances.

to:

    The behavior of unsafe functions, as defined by this section, is
    undefined when they are called from (or after a longjmp() or
    siglongjmp() out of) signal-catching functions in certain
    circumstances.

At page 3515 line 118392 section B.2.4.3 change:

    Note that longjmp() and siglongjmp() are not in the list of
    async-signal-safe functions.

to:

    Note that although longjmp() and siglongjmp() are in the list of
    async-signal-safe functions, there are restrictions on subsequent
    behavior after the function is called from a signal-catching
    function.

At page 3515 line 118400 section B.2.4.3 change:

    POSIX.1 does not define the behavior when any unsafe function is
    called in a signal handler that interrupts any unsafe function.

to:

    POSIX.1 does not define the behavior when any unsafe function is
    called in (or after a longjmp() or siglongjmp() out of) a signal
    handler that interrupts any unsafe function or the
    non-async-signal-safe processing equivalent to exit() that is
    performed after return from the initial call to main().

(0001198)
Don Cragun (manager)
2012-04-12 15:51
edited on: 2012-04-12 15:54

Interpretation response
------------------------
The standard is unclear on this issue, and no conformance distinction can be made between alternative implementations based on this. This is being referred to the sponsor.

Rationale:
-------------
The restrictions on using longjmp() and siglongjmp() are more restrictive than they need to be on POSIX systems. The loosened restrictions presented here do not break existing implementations and make it easier for application writers to create portable applications.

Notes to the Editor (not part of this interpretation):
-------------------------------------------------------
Make the changes presented in Note: 0001195

(0001293)
ajosey (manager)
2012-06-29 16:17

Interpretation proposed 29 June 2012 for final 45 day review
(0001356)
ajosey (manager)
2012-08-30 09:15

Interpretation approved 30 Aug 2012
(0003067)
dalias (reporter)
2016-02-07 01:41

The approved text is written from a standpoint that ignores the existence of threads. For instance it refers to returning from the initial invocation of main, but not returning from the thread start function for a non-initial thread, which would be just as unsafe (equivalent to pthread_exit, which is unsafe, and virtually impossible to implement safely). I believe this needs further review.
(0003069)
shware_systems (reporter)
2016-02-07 19:18
edited on: 2016-02-07 19:19

I think this clause in setjmp() is intended to cover that:
"If the most recent invocation of setjmp() with the corresponding jmp_buf occurred in another thread, or if there is no such invocation, or if the function containing the invocation of setjmp() has terminated execution in the interim, or if the invocation of setjmp() was within the scope of an identifier with variably modified type and execution has left that scope in the interim, the behavior is undefined."

where "if the (thread) function containing the invocation..." includes via pthread_exit() call or return at closing brace. I believe returning from main() is special, or any _Noreturn qualified interface, as the entire process is going zombie and may be invalidating what a thread considers static, as well as automatic, variables the jmp_buf references of the process state, including the structures managing active additional threads.

(0003070)
dalias (reporter)
2016-02-07 21:25

The reason returning from main is considered as special is that the effect is the same as calling exit. The exit function is AS-unsafe, so already covered by the general language that forbids calling AS-unsafe functions after such a longjmp, but returning from the initial invocation of main is not, in the abstract machine, a "call" to exit, despite likely being implemented as such, and thus requires a special case. A large part of what exit does requires locking and access to global data structures that cannot be made AS-safe in any reasonable way.

My point is that the same applies to return from the initial thread function for non-initial threads - returning is equivalent to (and likely implemented as) a call to pthread_exit, which is AS-unsafe, and which is required to perform a number of actions that cannot be made AS-safe in any reasonable way.

The language about calling AS-unsafe function "after" longjmp out of a signal handler is also imprecise in the context of a multithreaded program where the concept of "after" is not well-defined except within a single thread or in the presence of synchronization that imposes an order between actions by different threads. In particular, consider the case where thread A performs a longjmp out of a signal handler that interrupted an AS-unsafe function concurrently with thread B making calls to AS-unsafe functions. This should NOT result in undefined behavior, even if the calls in thread B happen "after" the longjmp in thread A; such an "after" relationship can be established by having thread A call sem_post (which is AS-safe) or synchronize via pipes or other AS-safe mechanisms after the longjmp. Such calls in thread B may stall waiting for a lock that was held by the interrupted AS-unsafe function in thread A, but that can happen anyway if the signal handler does not return; longjmp in itself is not the cause of the stall.
(0003071)
geoffclare (manager)
2016-02-08 09:46

The thread return case is already covered in the new normative text because it says "interrupted a non-async-signal-safe function or equivalent" and just gives the return from main() as an example of something that is equivalent to calling a non-async-signal-safe function. However, it may be worth including references to this case in the non-normative application usage and rationale additions. The new text is in TC2 draft 3 which is going to start review on Feb 19; the appropriate way to request an update to these additions would be to submit a new bug against the 2008-TC2 project, specifying the version as draft 3.
(0003072)
shware_systems (reporter)
2016-02-08 12:11

If a system allows the thread context to change before a signal function returns, normally or via a longjmp, it is up to it to manage any potential conflicts, as part of "unspecified" in what I cited. A system that doesn't allow switches to another thread, whether scheduling is preemptive or not, has "after" well-defined as a consequence. I said intended to point out that threading concerns aren't ignored by the interfaces, but I agree more could specified regardless of scheduling policy. Items like pipe handles are usually stored in effectively static arrays of the process state, accessible to any thread of the process by some method, not necessarily declared static.

- Issue History
Date Modified Username Field Change
2011-11-24 15:45 geoffclare New Issue
2011-11-24 15:45 geoffclare Status New => Under Review
2011-11-24 15:45 geoffclare Assigned To => ajosey
2011-11-24 15:45 geoffclare Name => Geoff Clare
2011-11-24 15:45 geoffclare Organization => The Open Group
2011-11-24 15:45 geoffclare Section => longjmp
2011-11-24 15:45 geoffclare Page Number => 1256
2011-11-24 15:45 geoffclare Line Number => 41378
2011-11-24 15:45 geoffclare Interp Status => ---
2011-11-25 08:35 Konrad_Schwarz Note Added: 0001053
2011-11-30 15:57 geoffclare Note Added: 0001070
2012-04-11 10:59 geoffclare Note Added: 0001195
2012-04-12 09:10 geoffclare Note Edited: 0001195
2012-04-12 15:51 Don Cragun Note Added: 0001198
2012-04-12 15:52 Don Cragun Interp Status --- => Pending
2012-04-12 15:52 Don Cragun Final Accepted Text => See bugnote:11894
2012-04-12 15:52 Don Cragun Status Under Review => Interpretation Required
2012-04-12 15:52 Don Cragun Resolution Open => Accepted As Marked
2012-04-12 15:52 Don Cragun Tag Attached: tc2-2008
2012-04-12 15:53 Don Cragun Final Accepted Text See bugnote:11894 => See Note: 0001198
2012-04-12 15:54 Don Cragun Note Edited: 0001198
2012-06-29 16:17 ajosey Interp Status Pending => Proposed
2012-06-29 16:17 ajosey Note Added: 0001293
2012-08-30 09:15 ajosey Interp Status Proposed => Approved
2012-08-30 09:15 ajosey Note Added: 0001356
2016-02-07 01:41 dalias Note Added: 0003067
2016-02-07 19:18 shware_systems Note Added: 0003069
2016-02-07 19:19 shware_systems Note Edited: 0003069
2016-02-07 21:25 dalias Note Added: 0003070
2016-02-08 09:46 geoffclare Note Added: 0003071
2016-02-08 12:11 shware_systems Note Added: 0003072
2019-06-10 08:55 agadmin Status Interpretation Required => Closed


Mantis 1.1.6[^]
Copyright © 2000 - 2008 Mantis Group
Powered by Mantis Bugtracker