2421. Non-specification of handling zero size in std::align [ptr.align]

Section: 20.2.5 [ptr.align] Status: New Submitter: Melissa Mears Opened: 2014-08-06 Last modified: 2014-11-03

Priority: 3

View all other issues in [ptr.align].

View all issues with New status.

Discussion:

The specification of std::align does not appear to specify what happens when the value of the size parameter is 0. (The question of what happens when alignment is 0 is mentioned in another Defect Report, 2377; it would change the behavior to be undefined rather than potentially implementation-defined.)

The case of size being 0 is interesting because the result is ambiguous. Consider the following code's output:

#include <cstdio>
#include <memory>

int main()
{
  alignas(8) char buffer[8];
  void *ptr = &buffer[1];
  std::size_t space = sizeof(buffer) - sizeof(char[1]);

  void *result = std::align(8, 0, ptr, space);

  std::printf("%d %td\n", !!result, result ? (static_cast<char*>(result) - buffer) : std::ptrdiff_t(-1));
}

There are four straightforward answers as to what the behavior of std::align with size 0 should be:

  1. The behavior is undefined because the size is invalid.

  2. The behavior is implementation-defined. This seems to be the status quo, with current implementations using #3.

  3. Act the same as size == 1, except that if size == 1 would fail but would be defined and succeed if space were exactly 1 larger, the result is a pointer to the byte past the end of the ptr buffer. That is, the "aligned" version of a 0-byte object can be one past the end of an allocation. Such pointers are, of course, valid when not dereferenced (and a "0-byte object" shouldn't be), but whether that is desired is not specified in the Standard's definition of std::align, it appears. The output of the code sample is "1 8" in this case.

  4. Act the same as size == 1; this means that returning "one past the end" is not a possible result. In this case, the code sample's output is "0 -1".

The two compilers I could get working with std::align, Visual Studio 2013 and Clang 3.4, implement #3. (Change %td to %Id on Visual Studio 2013 and earlier. 2014 and later will have %td.)

Proposed resolution: