*/ } ul /* Whole unordered list */ { } ul li /* Unordered list item */ { } ol /* Whole ordered list */ { } ol li /* Ordered list item */ { } hr {} /* ---- Some span elements --- */ sub /* Subscripts. Pandoc: H~2~O */ { } sup /* Superscripts. Pandoc: The 2^nd^ try. */ { } em /* Emphasis. Markdown: *emphasis* or _emphasis_ */ { } em > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } blockquote > * > p > ins > em /* Emphasis within emphasis: *This is all *emphasized* except that* */ { font-style: normal; } /* ---- Links (anchors) ---- */ a /* All links */ { /* Keep links clean. On screen, they are colored; in print, they do nothing anyway. */ text-decoration: none; } @media screen { a:hover { /* On hover, we indicate a bit more that it is a link. */ text-decoration: underline; } } @media print { a { /* In print, a colored link is useless, so un-style it. */ color: black; background: transparent; } a[href^="http://"]:after, a[href^="https://"]:after { /* However, links that go somewhere else, might be useful to the reader, so for http and https links, print the URL after what was the link text in parens */ content: " (" attr(href) ") "; font-size: 90%; } } /* ---- Images ---- */ img { /* Let it be inline left/right where it wants to be, but verticality make it in the middle to look nicer, but opinions differ, and if in a multi-line paragraph, it might not be so great. */ vertical-align: middle; } div.figure /* Pandoc figure-style image */ { /* Center the image and caption */ margin-left: auto; margin-right: auto; text-align: center; font-style: italic; } p.caption /* Pandoc figure-style caption within div.figure */ { /* Inherits div.figure props by default */ } /* ---- Code blocks and spans ---- */ pre, code { background-color: #fdf7ee; /* BEGIN word wrap */ /* Need all the following to word wrap instead of scroll box */ /* This will override the overflow:auto if present */ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ word-wrap: break-word; /* Internet Explorer 5.5+ */ /* END word wrap */ } pre /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.5em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 1px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.5em; margin-right: 0.5em; } pre.yacc, code.yacc { background-color: #f0f0f0; } pre.yacc /* Code blocks */ { /* Distinguish pre blocks from other text by more than the font with a background tint. */ padding: 0.0em; /* Since we have a background color */ border-radius: 5px; /* Softens it */ /* Give it a some definition */ border: 0px solid #aaa; /* Set it off left and right, seems to look a bit nicer when we have a background */ margin-left: 0.0em; margin-right: 0.0em; } @media screen { pre { white-space: pre; /* Dotted looks better on screen and solid seems to print better. */ border: 1px dotted #777; } } code /* All inline code spans */ { } p > code, li > code /* Code spans in paragraphs and tight lists */ { /* Pad a little from adjacent text */ padding-left: 2px; padding-right: 2px; } li > p code /* Code span in a loose list */ { /* We have room for some more background color above and below */ padding: 2px; } span.option { color: blue; text-decoration: underline; } /* ---- Math ---- */ span.math /* Pandoc inline math default and --jsmath inline math */ { /* Tried font-style:italic here, and it messed up MathJax rendering in some browsers. Maybe don't mess with at all. */ } div.math /* Pandoc --jsmath display math */ { } span.LaTeX /* Pandoc --latexmathml math */ { } eq /* Pandoc --gladtex math */ { } /* ---- Tables ---- */ /* A clean textbook-like style with horizontal lines above and below and under the header. Rows highlight on hover to help scanning the table on screen. */ table { border-collapse: collapse; border-spacing: 0; /* IE 6 */ border-bottom: 2pt solid #000; border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */ /* Center */ margin-left: auto; margin-right: auto; } thead /* Entire table header */ { border-bottom: 1pt solid #000; background-color: #eee; /* Does this BG print well? */ } tr.header /* Each header row */ { } tbody /* Entire table body */ { } /* Table body rows */ tr { } tr.odd:hover, tr.even:hover /* Use .odd and .even classes to avoid styling rows in other tables */ { background-color: #eee; } /* Odd and even rows */ tr.odd {} tr.even {} td, th /* Table cells and table header cells */ { vertical-align: top; /* Word */ vertical-align: baseline; /* Others */ padding-left: 0.5em; padding-right: 0.5em; padding-top: 0.2em; padding-bottom: 0.2em; } /* Removes padding on left and right of table for a tight look. Good if thead has no background color*/ /* tr td:last-child, tr th:last-child { padding-right: 0; } tr td:first-child, tr th:first-child { padding-left: 0; } */ th /* Table header cells */ { font-weight: bold; } tfoot /* Table footer (what appears here if caption is on top?) */ { } caption /* This is for a table caption tag, not the p.caption Pandoc uses in a div.figure */ { caption-side: top; border: none; font-size: 0.9em; font-style: italic; text-align: center; margin-bottom: 0.3em; /* Good for when on top */ padding-bottom: 0.2em; } /* ---- Definition lists ---- */ dl /* The whole list */ { border-top: 2pt solid black; padding-top: 0.5em; border-bottom: 2pt solid black; } dt /* Definition term */ { font-weight: bold; } dd+dt /* 2nd or greater term in the list */ { border-top: 1pt solid black; padding-top: 0.5em; } dd /* A definition */ { margin-bottom: 0.5em; } dd+dd /* 2nd or greater definition of a term */ { border-top: 1px solid black; /* To separate multiple definitions */ } /* ---- Footnotes ---- */ a.footnote, a.footnoteRef { /* Pandoc, MultiMarkdown footnote links */ font-size: small; vertical-align: text-top; } a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown, ?? footnote back links */ { } @media print { a[href^="#fnref"], a.reversefootnote /* Pandoc, MultiMarkdown */ { /* Don't display these at all in print since the arrow is only something to click on */ display: none; } } div.footnotes /* Pandoc footnotes div at end of the document */ { } div.footnotes li[id^="fn"] /* A footnote item within that div */ { } table tr td,th { border-right: 1px solid; border-left: 1px solid; } /* You can class stuff as "noprint" to not print. Useful since you can't set this media conditional inside an HTML element's style attribute (I think), and you don't want to make another stylesheet that imports this one and adds a class just to do this. */ @media print { .noprint { display:none; } }
2025-01-04
integration into IS ISO/IEC 9899:202y
document number | date | comment |
---|---|---|
n3447 | 202501 | Original proposal |
CC BY, see https://creativecommons.org/licenses/by/4.0
The recent campaign for slaying daemons has revealed that in fact some of the undefined behavior (UB) in the current C standard doesn’t even exist: some of the situations in J.2 that would in principle result in UB cannot trigger at all. The reason for these are misformulations in the normative text that seem to indicate UB where in fact there only are constraint violations or unspecified behavior.
We say that a semantic non-constraint requirement is a ghost-UB if no conforming program in any execution may ever violate it.
The present paper deals with ghost-UB that is attributed to constant expression, namely J.2 (50) to (53) in the current counting. The principal observation here to have is that the term “constant expression” is a syntax term and not a semantic term. So either an expression is a constant expression or it is isn’t and the difference between the two is not behavior (semantic) but syntax alone.
In fact all uses in the standard of the term are either covered by constraint violations (such as for array designators in initializers) or the fact if an expression is a constant expression (or not) then distinguishes different categories (such as VLA and arrays of known constant size). In all of these cases it makes no sense to speak of UB.
Additionally, the standard does not intend to leave constant expressions as a UB extension point: 6.6 p14 explicitly states that the use of extensions to the concept of constant expressions is implementation-defined.
Once convinced that we have ghost-UB the easiest way to deal with the situation is just to remove the useless listings (50) to (53) in J.2. We think that this alone would not be very user friendly and that users still would trip over the many “shall” that are confusingly applied in the text.
In fact, most of the text in 6.6 is even placed in the wrong category. The definitions made there are purely syntactical and convey no semantics beyond that. Thus we propose to reorder most of the text that then would appear under “Description” and only leave those entries that must in “Constraints” and “Semantics”. These deal with cases where the evaluated value does not fit:
Interesting for the latter, the implied UB didn’t even make it yet into J.2’s list, so we also add it, there.
Additionally:
We change the unfortunate formulation of “expressions not being evaluated” to a more precise formulation, namely we refer to operators that have an integer constant expression as result.
We improve footnote 117) a bit by adding constructs
such as (int*)nullptr
to the discussion and by constraining the discussion of the use case of
address constants to program or thread startup.
No normative change is intended by this paper.
New text is underlined green, removed text is
stroke-out red.
We propose to reorder this clause completely and to remove most “shall” by just factual description. This means the following is a complete replacement of the corresponding section (but subclause 6.6.1 should remain as it is now).
6.6 Constant expressions
Syntax
constant-expression: conditional-expression
Description
2 The fact that a given conditional expression forms a constant
expression is detected at translation time. In most of the cases the
value of the constant expression is also determined at translation time,
but values of address constants (or values that are derived from them)
are possibly only determined during linking or program startup. An
expression that evaluates to a constant is required in several contexts,
the most general form appears in initializers for objects for which the
value is determined at translation time or program startup such as
objects with static storage duration or with the constexpr
specifier.
3 A constant expression is a conditional expression that does not contain assignment, increment, decrement, function-call, or comma operators, except when they are contained within a subexpression that is by definition an integer constant expression.115) Additionally, such a constant expression is, or evaluates to, a null pointer constant (6.3.3.3) or one of the categories that are described in this clause:
- a compound literal constant,
- a named constant,
- an integer constant expression,
- an arithmetic constant expression,
- an address constant, or
- an address constant for a complete object type plus or minus an integer constant expression.
4 A compound literal with storage-class specifier constexpr
is a
compound literal constant, as is a postfix expression that
applies the . member access operator to a compound literal constant of
structure or union type, even recursively. A compound literal constant
is a constant expression with the type and value of the unnamed object.
5 An identifier that is:
- an enumeration constant,
- a predefined constant, or
- declared with storage-class specifier
constexpr
and has an object type,
is a named constant, as is a postfix expression that applies the.
member access operator to a named constant of structure or union type, even recursively. For enumeration and predefined constants, their value and type are defined in the respective clauses; forconstexpr
objects, such a named constant is a constant expression with the type and value of the declared object.
6 An integer constant expression116) has integer type and only has operands that are integer literals, named and compound literal constants of integer type, character literals,sizeof
or_Lengthof
expressions whose results are integer constant expressions,alignof
expressions, and floating, named, or compound literal constants of arithmetic type that are the immediate operands of casts. Cast operators in an integer constant expression only convert arithmetic types to integer types, except as part of an operand to the typeof operators,sizeof
operator,_Lengthof
operator, oralignof
operator.
7 An arithmetic constant expression has arithmetic type and only has operands that are integer literals, floating literals, named or compound literal constants of arithmetic type, character literals,sizeof
and_Lengthof
expressions whose results are integer constant expressions, andalignof
expressions. Cast operators in an arithmetic constant expression only convert arithmetic types to arithmetic types, except as part of an operand to the typeof operators,sizeof
operator,_Lengthof
operator, oralignof
operator.
8 An address constant is a null pointer,117) a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it is created explicitly using the unary&
operator or an integer constant cast to pointer type, or implicitly using an expression of array or function type. The array-subscript[]
and member-access->
operator, the address&
and indirection*
unary operators, and pointer casts can be used in the creation of an address constant, if the value of an object is not accessed by use of these operators.118)
9 A structure or union constant is a named constant or
compound literal constant with structure or union type, respectively.
Starting from a structure or union constant, the member-access .
operator can be
used to form a named constant or compound literal constant as described
previously in this subclause; here, for a union constant, only the
member that is initialized by the union constant’s initializer can be
used.
10 An implementation may accept other forms of constant expressions, called extended constant expressions. It is implementation-defined whether extended constant expressions are usable in the same manner as the constant expressions defined in this document, including whether or not extended integer constant expressions are considered to be integer constant expressions.119)
Constraints
11 Each constant expression shall evaluate to a constant that is in the range of representable values for its type.
Semantics
12 If a floating expression is evaluated in the translation environment, the arithmetic range and precision shall be at least as great as if the expression were being evaluated in the execution environment.120)
13 The semantic rules for the evaluation of a constant expression are the same as for nonconstant expressions.121)
Forward references: array declarators (6.7.7.3), initialization (6.7.11).
The footnotes are as follows:
115) The typeof andalignof
operators and many instances ofsizeof
and_Lengthof
operators are by definition integer constant expressions (6.7.3.6) and thus their operands are not evaluated (6.5.4.5).
116) An integer constant expression is required in contexts such as the size of a bit-field member of a structure, the value of an enumeration constant, and the size of a non-variable length array. Specific rules to determine the value and specific constraints that apply to the integer constant expressions used in conditional-inclusion preprocessing directives are discussed in 6.10.2.
117) A named constant or compound literal constant of integer
type and value zero is a null pointer constant. A named constant or
compound literal constant with a pointer type and a value null or the
constant nullptr
cast to a
pointer type are null pointers but not null pointer constants; they can
only be used to initialize a pointer object at program or thread startup
if its type implicitly converts to the target type.
118) Named constants or compound literal constants with arithmetic type, including names of constexpr objects, are valid in offset computations such as array subscripts or in pointer casts, as long as the expressions in which they occur form integer constant expressions. In contrast, names of other objects, even if const-qualified and with static storage duration, are not valid.
119) For example, in the declarationint arr_or_vla[(int)+1.0];
, while possible to be computed by some implementations as an array with a size of one, it is implementation-defined whether this results in a variable length array declaration or a declaration of an array of known constant size of automatic storage duration. The choice depends on whether(int)+1.0
is an extended integer constant expression.
120) The use of evaluation formats as characterized byFLT_EVAL_METHOD
andDEC_EVAL_METHOD
also applies to evaluation in the translation environment.
121) Thus, in the following initialization,
the expression is a valid integer constant expression with value one.
Remove the following four entries
(50) An expression that is required to be an integer constant expression does not have an integer type; has operands that are not integer literals, named constants, compound literal constants, enumeration constants, character literals, predefined constants,sizeof
or_Lengthof
expressions whose results are integer constant expressions,alignof
expressions, or immediately-cast floating literals; or contains casts (outside operands tosizeof
,_Lengthof
andalignof
operators) other than conversions of arithmetic types to integer types (6.6).
(51) A constant expression in an initializer is not, or does not evaluate to, one of the following: a named constant, a compound literal constant, an arithmetic constant expression, a null pointer constant, an address constant, or an address constant for a complete object type plus or minus an integer constant expression (6.6).
(52) An arithmetic constant expression does not have arithmetic type; has operands that are not integer literals, floating literals, named and compound literal constants of arithmetic type, character literals, predefined constants,sizeof
or_Lengthof
expressions whose results are integer constant expressions, oralignof
expressions; or contains casts (outside operands tosizeof
oralignof
operators) other than conversions of arithmetic types to arithmetic types (6.6).
(53) The value of an object is accessed by an array-subscript[]
, member-access.
or->
, address&
, or indirection*
operator or a pointer cast in creating an address constant (6.6).
Add one new entry
(50′) The value of a floating expression as determined in the translation environment in the context of the evaluation of a constant expression is outside the arithmetic range or has less precision than if it were evaluated in the execution environment (6.6).
There is a branch on WG14’s gitlab that reflects the proposed changes:
https://gitlab.gwdg.de/iso-c/draft/-/tree/ce-UB
Thanks to Martin Uecker for review and discussions.