On 03/08/13 20:58, Mcdaniel, Daryl wrote:
> A compiler that optimizes out references to NULL is doing the wrong
> thing.
It depends.
> The ISO/IEC 9899:199409 (C95) language specification says nothing
> about using volatile with NULL.
>
> The language specification does NOT prohibit reading from, writing to,
> or executing a function that is located at, address 0.
> It does prohibit the compiler from placing data or functions at that
> location.
>
> It sounds like clang is broken if it doesn't have an option to disable
> the behavior you are reporting.
> Changing references through a NULL pointer to a trap would be a
> nonstandard extension.
>From ISO C99:
3.4
1 behavior
external appearance or action
3.4.1
1 implementation-defined behavior
unspecified behavior where each implementation documents how the
choice is made
2 EXAMPLE An example of implementation-defined behavior is the
propagation of the high-order bit when a signed integer is shifted
right.
3.4.3
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct
or of erroneous data, for which this International Standard imposes
no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during
translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message).
3.4.4
1 unspecified behavior
behavior where this International Standard provides two or more
possibilities and imposes no further requirements on which is chosen
in any instance
2 EXAMPLE An example of unspecified behavior is the order in which the
arguments to a function are evaluated.
4. Conformance
2 If a "shall" or "shall not" requirement that appears outside of a
constraint is violated, the behavior is undefined. Undefined
behavior is otherwise indicated in this International Standard by
the words "undefined behavior" or by the omission of any explicit
definition of behavior. There is no difference in emphasis among
these three; they all describe "behavior that is undefined".
A platform may define things that the ISO C99 standard leaves undefined;
it can say "SIGSEV" for example. But that doesn't make the program any
more conformant to / any less erroneous in ISO C99.
What the "platform defines" outside of C99 may depend on several factors
at once, for example, compiler options (-fdelete-null-pointer-checks),
SIGSEGV vs. something else etc. (A strict C99-only compiler might even
refuse *not* to break undefined behavior on purpose, and it would be a
perfectly fine (and very useful) C99 compiler.)
Observable behavior will result from several layers of behavior
definitions. When clang is told (with compiler switches or otherwise) to
consider nothing else than ISO C99, then it is free to "implement"
undefined behavior however it wishes, because (a) C99 doesn't cover
those gaps, and (b) clang was told to consider nothing else.
When targeting one specific platform (= knowing and/or controlling all
"layers"), the difference between the C99 terms
"implementation-defined", "unspecified", "undefined" may not be
important; whatever falls "through" C99 might be caught (defined) by
another layer: POSIX, the Single Unix Specification, compiler switches,
compiler documentation, happenstance in compiler source code, operating
system specifics, etc.
The terms are important when the source code is moved to another
platform (compiler upgrade, operating system upgrade, fully foreign
platform), and we only know that the new target "supports C99". Then
bits exploiting "implementation-defined behavior" can be adapted in
accordance with target documentation (there will be documentation).
Unspecified behavior could change without documentation, but we've been
warned: eg. we're free to call functions with arguments, and to evaluate
expressions, but we should write them so that we're happy with whichever
order evaluation takes place in. Using the facility is not a programming
error in itself.
Bits that rely on undefined behavior could break irrevocably, but we've
been told never to do those things *if* we intended to build our program
on another platform that calls itself C99 conformant *and nothing else
in addition*.
(The same thing works with other standards that build upon ISO C99 and
use the same terminology; for example the Single Unix Specification,
Version 3: you can expect the same levels of assurance when moving from
one SUSv3 system to another SUSv3 system, only the precise contents of
each "level" is different than in ISO C99.)
In ISO C99, dereferencing a null pointer is undefined behavior.
(Additionally, the pointer target being volatile-qualified doesn't
change that.)
6.3.2.3 Pointers
3 An integer constant expression with the value 0, or such an
expression cast to type void *, is called a null pointer constant.
[...] If a null pointer constant is converted to a pointer type, the
resulting pointer, called a null pointer, is guaranteed to compare
unequal to a pointer to any object or function.
6.5.3.2 Address and indirection operators
4 The unary * operator denotes indirection. If the operand points to a
function, the result is a function designator; if it points to an
object, the result is an lvalue designating the object. If the
operand has type "pointer to type", the result has type "type". If
an invalid value has been assigned to the pointer, the behavior of
the unary * operator is undefined.83)
Footnote 83
[...] Among the invalid values for dereferencing a pointer by the
unary * operator are a null pointer, an address inappropriately
aligned for the type of object pointed to, and the address of an
object after the end of its lifetime.
6.5.2.3 Structure and union members
4 A postfix expression followed by the -> operator and an identifier
designates a member of a structure or union object. The value is
that of the named member of the object to which the first expression
points, and is an lvalue. [...]
(A null pointer cannot point to an object (see 6.3.2.3p3 above),
therefore "nullptr->member" is undefined behavior by omission of any
explicit definition of behavior in 6.5.2.3p4.)
Regarding "address 0":
- not required: all-bits-clear object representation in a null pointer,
- not required: (uintptr_t)(void*)0 == 0 -- supposing uintptr_t is
supported at all.
They are permitted, naturally:
6.3.2.3 Pointers
5 An integer may be converted to any pointer type. Except as
previously specified, the result is implementation-defined, might
not be correctly aligned, might not point to an entity of the
referenced type, and might be a trap representation.56)
6 Any pointer type may be converted to an integer type. Except as
previously specified, the result is implementation-defined. If the
result cannot be represented in the integer type, the behavior is
undefined. The result need not be in the range of values of any
integer type.
Footnote 56
The mapping functions for converting a pointer to an integer or an
integer to a pointer are intended to be consistent with the
addressing structure of the execution environment.
(Footnotes, notes, examples are not normative but informative only --
they don't prescribe, only explain.)
All this is just my opinion of course.
Laszlo
------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
endpoint security space. For insight on selecting the right partner to
tackle endpoint security challenges, access the full report.
http://p.sf.net/sfu/symantec-dev2dev
_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/edk2-devel