Bug 29399 - Wrong definition of setjmp
Summary: Wrong definition of setjmp
Status: REOPENED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL: https://www.gnu.org/software/libc/man...
Keywords:
Depends on:
Blocks:
 
Reported: 2022-07-24 19:25 UTC by Pavel M
Modified: 2022-08-23 08:12 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2022-07-24 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Pavel M 2022-07-24 19:25:33 UTC
The setjmp is defined as:
#define setjmp(env)	_setjmp (env)

This is wrong because it breaks the following code:
#include <setjmp.h>

void f(void)
{
    struct { int x; } _setjmp;
    jmp_buf x;
    setjmp(x);
}

In file included from <source>:1:
<source>: In function 'f':
<source>:7:5: error: called object '_setjmp' is not a function or function pointer
    7 |     setjmp(x);
      |     ^~~~~~
<source>:5:23: note: declared here
    5 |     struct { int x; } _setjmp;
      |                       ^~~~~~~
Compiler returned: 1
Comment 1 Dmitry V. Levin 2022-07-24 21:34:25 UTC
"reserved names include all external identifiers (global functions and variables) that begin with an underscore (‘_’) [...]. This is so that the library and header files can define functions, variables, and macros for internal purposes without risk of conflict with names in user programs."
Comment 2 Pavel M 2022-07-24 22:06:47 UTC
Why it was resolved as INVALID? Per C identifier with block scope that begins with an underscore, followed by a lowercase letter (e.g. _setjmp) is not reserved. So the user may use _setjmp for its own purposes. Please reconsider.
Comment 3 Andreas Schwab 2022-07-24 22:09:14 UTC
The name is only reserved in file scope.
Comment 4 Pavel M 2022-07-28 16:33:43 UTC
Another example:
#define _setjmp 0
#include <setjmp.h>

void f(void)
{
    jmp_buf x;
    setjmp(x);
}

<source>:1:17: error: expected identifier or '(' before numeric constant
    1 | #define _setjmp 0
      |                 ^
<source>: In function 'f':
<source>:1:17: error: called object is not a function or function pointer
    1 | #define _setjmp 0
      |                 ^
/usr/include/setjmp.h:62:25: note: in expansion of macro '_setjmp'
   62 | #define setjmp(env)     _setjmp (env)
      |                         ^~~~~~~
Compiler returned: 1

Per C all identifiers that begin with an underscore, followed by a lowercase letter AND used as macros are non-reserved.
Comment 5 Florian Weimer 2022-07-28 16:50:13 UTC
I think C11 is ambiguous whether macros like _setjmp have file scope or not and are thus reserved or not. It really only makes sense to treat macros as having file scope for the purpose of identifier reserved-ness, so the example in comment 4 is invalid (but the one in comment 0 is valid).

Has the scope of macros been clarified in later versions of the C standard?
Comment 6 Zack Weinberg 2022-07-28 19:38:58 UTC
I don't think the standard is ambiguous at all.  Its wording could be improved, but there's only one interpretation that makes sense.

Since at least C11, section 7.1.3p2 reads in part

> If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), **or defines a reserved identifier as a macro name**, the behavior is undefined.

The clause set off by double asterisks doesn't make any sense unless "a reserved identifier" is understood broadly: if the program defines an identifier that is reserved *in any context* as macro name, the behavior is undefined.

To put it another way, I believe the intent of this sentence is that any identifier that is reserved in any phase-7 context is also, unconditionally, reserved for use as a macro name.

---

The program in comment 4 defines a reserved identifier as a macro name, and is therefore invalid.  The program in comment 0, on the other hand, doesn't define any macros; it defines a *local variable*, using a name that is reserved for use by the implementation *only* at file scope.  This clashes with setjmp.h assuming that the `_setjmp` in the expansion of the `setjmp` macro will refer to a global symbol.  I think this *is* a bug in glibc's setjmp.h.  The thing it's doing with macros should be done with __REDIRECT instead.
Comment 7 Pavel M 2022-07-29 06:53:29 UTC
Macros don't have file scope. The scope of macro definitions is defined in C11, 6.10.3.5.

The program in comment 4 defines a non-reserved identifier as a macro name, and is therefore valid.

P.J. Plauger, Standard C Library Name Space Control, JCLT, 1(4), page 251:
> Remember that the user can write macros that begin with an underscore, followed by a lowercase letter.
Comment 8 Florian Weimer 2022-07-29 12:25:55 UTC
(In reply to Zack Weinberg from comment #6)
> I don't think the standard is ambiguous at all.  Its wording could be
> improved, but there's only one interpretation that makes sense.
> 
> Since at least C11, section 7.1.3p2 reads in part
> 
> > If the program declares or defines an identifier in a context in which it is reserved (other than as allowed by 7.1.4), **or defines a reserved identifier as a macro name**, the behavior is undefined.
> 
> The clause set off by double asterisks doesn't make any sense unless "a
> reserved identifier" is understood broadly: if the program defines an
> identifier that is reserved *in any context* as macro name, the behavior is
> undefined.

On the other hand, 6.2.1p1 refuses to define scope for macro names and macro parameters, so it's hard to see how the an “identifier with file scope” could refer to a macro name.

I think 7.1.3 leaves something to be desired anyway because it makes it pretty clear that this is valid:

#define tm_sec puts ("Hello, world!")
#include <time.h>

int
main (void)
{
  tm_sec;
  return 0;
}

But to implement that, we would have to use non-standard preprocessor features (#pragma push_macro, #pragma pop_macro).

(Historically, structure fields had file scope (similar to some ML flavors), but that hasn't been true for a long, long time.)
Comment 9 Pavel M 2022-07-29 14:03:35 UTC
The term "file scope" (6.2.1/4) is relevant only at translation phase 7. The "preprocessing directives are executed, macro invocations are expanded" at translation phase 4. At translation phase 4 there is no "identifier with file scope" because there is no "file scope".
Comment 10 Andreas Schwab 2022-07-29 15:53:02 UTC
1.7.3#2 does not mention any context for the identifiers that may not be defined as macros.
Comment 11 Zack Weinberg 2022-08-21 18:06:57 UTC
(In reply to Florian Weimer from comment #8)
> (In reply to Zack Weinberg from comment #6)
> > > If the program declares or defines an identifier in a context in
> > > which it is reserved (other than as allowed by 7.1.4),
> > > **or defines a reserved identifier as a macro name**,
> > > the behavior is undefined.
> > 
> > The clause set off by double asterisks doesn't make any sense unless "a
> > reserved identifier" is understood broadly: if the program defines an
> > identifier that is reserved *in any context* as macro name, the behavior is
> > undefined.
> 
> On the other hand, 6.2.1p1 refuses to define scope for macro names and macro
> parameters, so it's hard to see how the an “identifier with file scope”
> could refer to a macro name.

Yes, that's why it's an OR. If the program (does an irrelevant thing) OR (defines a reserved identifier as a macro name), the behavior is undefined.

(Pavel M from comment #9)
> At translation phase 4 there is no "identifier with
> file scope" because there is no "file scope".

Indeed. Scope cannot be a factor in the macro case, because there is no such thing as scope during translation phase 4. Thus, the only interpretation of "if the program defines a reserved identifier as a macro name" that makes sense is "if the program defines *any* reserved identifier, *regardless* of the phase-7 context where it is reserved, as a macro name".

(Florian Weimer from comment #8)
> ... this is valid:
> #define tm_sec puts ("Hello, world!")
> #include <time.h>
> int
> main (void)
> {
>   tm_sec;
>   return 0;
> }

How did you get that this is valid? It looks invalid to me.
Comment 12 Florian Weimer 2022-08-22 06:35:07 UTC
(In reply to Zack Weinberg from comment #11)
> (Florian Weimer from comment #8)
> > ... this is valid:
> > #define tm_sec puts ("Hello, world!")
> > #include <time.h>
> > int
> > main (void)
> > {
> >   tm_sec;
> >   return 0;
> > }
> 
> How did you get that this is valid? It looks invalid to me.

I think the list of reserved identifiers in 7.1.3p1 is exhaustive. tm_sec does not have file scope or external linkage, nor is it reserved as a macro name, so I don't see how it can be a reserved identifier.
Comment 13 Andreas Schwab 2022-08-22 09:09:38 UTC
tm_ is a reserved prefix for <time.h>.
Comment 14 Florian Weimer 2022-08-22 09:19:42 UTC
(In reply to Andreas Schwab from comment #13)
> tm_ is a reserved prefix for <time.h>.

Isn't that specific to POSIX? But even POSIX does not make quot (as used in div_t) a reserved identifier.
Comment 15 Andreas Schwab 2022-08-22 16:46:25 UTC
Since the names of the div_t members are required there must be something that protects them.
Comment 16 Zack Weinberg 2022-08-22 16:52:35 UTC
At this point I think someone needs to file a DR and get the wording of the standard, wrt reserved identifiers and user-defined macros, clarified.  I'm in agreement with Andreas that *something* must be protecting standard-specified structure field names from user macros, but I can also see where Florian is coming from when he says he doesn't see any text in the standard that makes that requirement.

Can we separate the case described in comment 0 from the case described in comment 4, though?  The comment 0 case does not involve user-defined macros and I think Pavel M is right that use of `_setjmp` as a *local variable* name is legitimate.
Comment 17 Andreas Schwab 2022-08-22 17:00:21 UTC
7.1.3 says that file scope identifiers are reserved for macro use, and all structures in the C standard are declared at file scope, which protects them (including their members).  This makes #c8 non-conforming.
Comment 18 jsm-csl@polyomino.org.uk 2022-08-22 17:08:46 UTC
On Mon, 22 Aug 2022, zack+srcbugz at owlfolio dot org via Glibc-bugs wrote:

> At this point I think someone needs to file a DR and get the wording of the
> standard, wrt reserved identifiers and user-defined macros, clarified.  I'm in

Make that "file a National Body comment against the C23 CD once that 
ballot opens" (there isn't currently an issue tracking process running, 
and we didn't have time at the July meeting to discuss the N3002 issue 
tracking proposal, but NB comments aren't limited to changes in C23 - they 
can be for issues still present in the C23 draft but that were also in 
older standard versions).
Comment 19 Zack Weinberg 2022-08-22 18:47:17 UTC
FYI, I have no affiliation whatsoever with WG14; whatever the proper procedure is for reporting the issue to the committee, someone besides me is going to have to do it.
Comment 20 Florian Weimer 2022-08-23 08:12:49 UTC
(In reply to Andreas Schwab from comment #17)
> 7.1.3 says that file scope identifiers are reserved for macro use, and all
> structures in the C standard are declared at file scope, which protects them
> (including their members).  This makes #c8 non-conforming.

You are right. Identifiers of structure members do have file scope. It's certainly a surprising wording. Conflicts are resolved through namespaces. So member names reserved if the header is included.