Austin Group Defect Tracker

Aardvark Mark IV


Viewing Issue Simple Details Jump to Notes ] Issue History ] Print ]
ID Category Severity Type Date Submitted Last Update
0000940 [1003.1(2013)/Issue7+TC1] Base Definitions and Headers Objection Enhancement Request 2015-04-24 23:17 2020-04-08 15:25
Reporter eblake View Status public  
Assigned To
Priority normal Resolution Accepted As Marked  
Status Applied  
Name Eric Blake
Organization Red Hat
User Reference ebb.null
Section XBD 3.245
Page Number 71
Line Number 2075
Interp Status ---
Final Accepted Text Note: 0002696
Summary 0000940: all 0 bits should be a null pointer on POSIX systems
Description The C standard goes to great length to ensure that NULL (and for that matter, any representation of the null pointer, which is written in source code by converting a constant value 0 to a pointer) need not be represented in hardware by all 0 bits (that is, 'int *p = 0;' or 'static int *p;' is allowed to compile to assembly instructions that assign a non-zero bit pattern to the location named p). And in fact, there are historical machines where the most efficient null pointer in hardware was indeed a non-zero bit pattern: http://c-faq.com/null/machexamp.html [^]

However, POSIX already has a number of constraints that restrict things to a smaller set of hardware than what is allowed by the C standard, such as requiring 'char' to be exactly 8 bits (and not larger), requiring 'unsigned int' to be at least 32 bits (rather than at least 16), or requiring that a pointer to function can be converted into a void* and back without loss of information.

These days, all known systems that have attempted to reach POSIX compliance have been implemented on hardware where the machine is more efficient when using the all-zero representation as a null pointer. Also, coders have grown accustomed to using calloc() or memset(,0,) to initialize null pointer values into objects that contain pointer members. If the compiler is allowed to choose a non-zero bit pattern for the null pointer, then such code must instead use explicit initializers (and rely on default-initialization of all remaining members) or use assignment copy from default-initialized static storage to ensure that pointer members are initialized to the null pointer (that is, if the null pointer is not the all-zero bit pattern, then any action that assigns a pointer to an all-zero pattern causes the pointer member to have an undefined value).

As a final argument in favor of adding this requirement in the next version of POSIX, suppose that someone is trying to implement POSIX on hardware that has with more efficient support for a non-zero bit pattern as the preferred null pointer. It is still possible to implement a compiler to emit code that treats the all-zero pattern and the hardware-specific pattern as both being null pointers, as long as the emitted instructions treat both patterns compare equal to each other and unequal to any actual object. Of course, the quality and performance of code on such a machine may be worse, because it costs more instructions to check for two rather than one value of the null pointer, but the point remains that compiler writers can still isolate the user from hardware quirks while still making nice guarantees about all-zero initialization.
Desired Action At page 72 line 2078 (XBD 3.245 Null Pointer), add a sentence:
POSIX additionally guarantees that any pointer object initialized by memset() to 0 or by calloc() will be interpreted as a null pointer.


At page 345 line 11565 (XBD <stddef.h> DESCRIPTION), inside CX shading, add a sentence:
Additionally, any pointer object initialized to an all-zero value, such as by memset() to 0 or by calloc(), shall be treated as a null pointer.


After page 345 line 11587 (XBD <stddef.h> RATIONALE), add a paragraph:
Likewise, the ISO C standard does not require a pointer object initialized to an all-zero value to be treated as a NULL pointer. However, while there has been historical hardware where non-zero patterns were more efficient for use as the canonical null pointer, no known POSIX system has tried to target such hardware. However, while unlikely in modern hardware, a compiler is still allowed to treat more than one bit pattern as a representation of the null pointer (all such patterns will compare equal to one another, and unequal to any pointer to any other object), so applications should not assume that a non-zero pointer value cannot be treated as a null pointer (in reality, the only way an application can get at the bit pattern stored in a pointer object involves undefined behavior in C, such as aliasing through a union).
Tags issue8
Attached Files

- Relationships
related to 0000934Closed Requirement for zeroing the sockaddr_in and sockaddr_un structures. 

-  Notes
(0002638)
mdempsky (reporter)
2015-04-24 23:40

> (in reality, the only way an application can get at the bit pattern
> stored in a pointer object involves undefined behavior in C, such as
> aliasing through a union)

This remark seems wrong to me. Isn't this a valid way to observe a null pointer's object representation?

  void *p = 0;
  char b[sizeof(p)];
  memcpy(b, &p, sizeof(b));
  for (size_t i = 0; i < sizeof(b); i++)
    printf("%d\n", b[i]);
(0002639)
dalias (reporter)
2015-04-24 23:43

Indeed it's wrong for exactly that reason. C explicitly permits the inspection of the representation of any object as an overlaid array of type unsigned char [sizeof object]. memcpy is not even needed here.
(0002641)
shware_systems (reporter)
2015-04-29 07:44

yes, you can do that to get what the compiler reports as the null pointer, but what the code dereferencing that pointer actually uses may be something else entirely - as a simple case it may add the null reported to a constant base address after all the static const declares, as the start of writable memory. It only guarantees that pointer arithmetic is plausible with declared types, such as char array references, not void or null
(0002676)
rhansen (manager)
2015-05-21 16:53
edited on: 2015-05-21 16:54

At page 72 line 2078 (XBD 3.245 Null Pointer), add a sentence:
POSIX additionally guarantees that any pointer object whose representation has all bits set to zero, perhaps by memset() to 0 or by calloc(), will be interpreted as a null pointer.
At page 345 line 11565 (XBD <stddef.h> DESCRIPTION), inside CX shading, add a sentence:
Additionally, any pointer object whose representation has all bits set to zero, perhaps by memset() to 0 or by calloc(), shall be treated as a null pointer.
After page 345 line 11587 (XBD <stddef.h> RATIONALE), add a paragraph:
Likewise, the ISO C standard does not require a pointer object whose representation has all bits set to zero to be treated as a null pointer. While there has been historical hardware where non-zero patterns were more efficient for use as the canonical null pointer, no known POSIX system has tried to target such hardware. However, though unlikely in modern hardware, a compiler is still allowed to treat more than one bit pattern as a representation of the null pointer (all such patterns will compare equal to one another, and unequal to any pointer to any other object). Thus, applications should not assume that a pointer object with non-zero representation is not a null pointer.


(0002696)
geoffclare (manager)
2015-06-04 15:53
edited on: 2015-06-04 15:55

At page 72 line 2078 (XBD 3.245 Null Pointer), add a sentence:
POSIX additionally guarantees that any pointer object whose representation has all bits set to zero, perhaps by memset() to 0 or by calloc(), will be interpreted as a null pointer.

On page 107 after line 2884 (4.x General Concepts) in the section added by 0000934, change:
<small>Note: If an implementation treats the all-zero bit pattern of a pointer object as a null pointer, and the all-zero bit pattern of a floating point object as equivalent to positive 0, then memset() to zero and calloc() have the same effects as default initialization for all named members of a structure. [MX]Implementations that define __STDC_IEC_559__ guarantee that the all-zero bit pattern of a floating point object represents 0.0.[/MX]</small>

to:
<small>Note: If an implementation treats the all-zero bit pattern of a floating point object as equivalent to positive 0, then memset() to zero and calloc() have the same effects as default initialization for all named members of a structure. [MX]Implementations that define __STDC_IEC_559__ guarantee that the all-zero bit pattern of a floating point object represents 0.0.[/MX]</small>

On Page: 303 Line: 10107 (XBD <netdb.h> DESCRIPTION), add a new paragraph:
The addrinfo structure shall not include any additional members which have a floating-point type if an object of that type with an all-bits-zero representation does not have the value 0.0. [MX]Implementations that define __STDC_IEC_559__ are required to treat the all-zero bit pattern for a floating point object as a representation of 0.0, and may therefore have floating-point type members.[/MX]

On Page: 305 Line: 10180 (XBD <netdb.h> APPLICATION USAGE), change:
None.

to:
The requirement that addrinfo does not include any additional members which have a floating-point type if an object of that type with an all-bits-zero representation does not have the value 0.0 is to allow initialization of an addrinfo hints structure (see XSH freeaddrinfo()) using:
struct addrinfo hints;

memset(&hints, 0, sizeof hints);
as an alternative to the use of default initialization.

On Page: 306 Line: 10236 (XBD <netinet/in.h> DESCRIPTION), add a new paragraph:
The sockaddr_in6 structure shall not include any additional members which have a floating-point type if an object of that type with an all-bits-zero representation does not have the value 0.0. [MX]Implementations that define __STDC_IEC_559__ are required to treat the all-zero bit pattern for a floating point object as a representation of 0.0, and may therefore have floating-point type members.[/MX]

On Page: 309 Line: 10323 (XBD <netinet/in.h> APPLICATION USAGE), after applying 0000934 change:
Although it is common practice to initialize a sockaddr_in6 structure using:
struct sockaddr_in6 sa;

memset(&sa, 0, sizeof sa);
this method is not portable according to this standard, because the structure can contain pointer or floating point members that are not required to have an all-bits-zero representation after default initialization. Portable methods make use of default initialization, for example:
struct sockaddr_in6 sa = { 0 };
or:
static struct sockaddr_in6 sa_init;

struct sockaddr_in6 sa = sa_init;

A future version of this standard may require that a pointer object with an all-bits-zero representation is a null pointer, and that sockaddr_in6 does not have any floating-point members if a floating-point object with an all-bits-zero representation does not have the value 0.0.

to:
The requirement that sockaddr_in6 does not include any additional members which have a floating-point type if an object of that type with an all-bits-zero representation does not have the value 0.0 is to allow initialization of a sockaddr_in6 structure using:
struct sockaddr_in6 sa;

memset(&sa, 0, sizeof sa);
as an alternative to the use of default initialization.

At page 345 line 11565 (XBD <stddef.h> DESCRIPTION), inside CX shading, add a sentence:
Additionally, any pointer object whose representation has all bits set to zero, perhaps by memset() to 0 or by calloc(), shall be treated as a null pointer.

After page 345 line 11587 (XBD <stddef.h> RATIONALE), add a paragraph:
Likewise, the ISO C standard does not require a pointer object whose representation has all bits set to zero to be treated as a null pointer. While there has been historical hardware where non-zero patterns were more efficient for use as the canonical null pointer, no known POSIX system has tried to target such hardware. However, though unlikely in modern hardware, a compiler is still allowed to treat more than one bit pattern as a representation of the null pointer (all such patterns will compare equal to one another, and unequal to any pointer to any other object). Thus, applications should not assume that a pointer object with non-zero representation is not a null pointer.

On page 928 line 31296 (XSH freeaddrinfo() APPLICATION USAGE), after applying 0000934 change:
Although it is common practice to initialize the hints structure using:
struct addrinfo hints;

memset(&hints, 0, sizeof hints);
this method is not portable according to this standard, because the structure can contain pointer or floating point members that are not required to have an all-bits-zero representation after default initialization. Portable methods make use of default initialization, for example:
struct addrinfo hints = { 0 };
or
static struct addrinfo hints_init;

struct addrinfo hints = hints_init;
A future version of this standard may require that a pointer object with an all-bits-zero representation is a null pointer, and that addrinfo does not have any floating-point members if a floating-point object with an all-bits-zero representation does not have the value 0.0.

to:
The hints structure can be initialized using <tt>memset(&hints, 0, sizeof hints);</tt> or by default initialization (see the APPLICATION USAGE for XBD <netdb.h>).


(0004823)
geoffclare (manager)
2020-04-08 15:25

When applying this bug I left off the MX shading on the small-font note in XBD 4.2 since the text is non-normative and therefore shading it is not appropriate. It already refers to the __STDC_IEC_559__ macro and so no change to the text itself was needed.

- Issue History
Date Modified Username Field Change
2015-04-24 23:17 eblake New Issue
2015-04-24 23:17 eblake Name => Eric Blake
2015-04-24 23:17 eblake Organization => Red Hat
2015-04-24 23:17 eblake User Reference => ebb.null
2015-04-24 23:17 eblake Section => XBD 3.245
2015-04-24 23:17 eblake Page Number => 71
2015-04-24 23:17 eblake Line Number => 2075
2015-04-24 23:17 eblake Interp Status => ---
2015-04-24 23:40 mdempsky Note Added: 0002638
2015-04-24 23:43 dalias Note Added: 0002639
2015-04-26 13:57 eblake Relationship added related to 0000934
2015-04-29 07:44 shware_systems Note Added: 0002641
2015-05-14 15:31 Don Cragun Desired Action Updated
2015-05-21 16:53 rhansen Note Added: 0002676
2015-05-21 16:54 rhansen Note Edited: 0002676
2015-06-04 15:53 geoffclare Note Added: 0002696
2015-06-04 15:55 geoffclare Note Edited: 0002696
2015-06-04 15:57 geoffclare Final Accepted Text => Note: 0002696
2015-06-04 15:57 geoffclare Status New => Resolved
2015-06-04 15:57 geoffclare Resolution Open => Accepted As Marked
2015-06-04 15:57 geoffclare Tag Attached: issue8
2020-04-08 15:25 geoffclare Note Added: 0004823
2020-04-08 15:25 geoffclare Status Resolved => Applied


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