revised questions for X3J11 interpretation (fwd)

Tom MacDonald uunet!fig.cray.com!tam
Thu Jan 2 07:46:11 PST 1992


Hello Tom,

Happy Holidays.  Bill Homer and I have been working on some questions for
X3J11 to ponder.  Essentially this has to do with aliasing issues in the
Standard C library.  I have enclosed the questions for you.  I want to submit
this for formal interpretation by X3J11.  Can you let me know exactly what
steps I need to take before this can considered at the next X3J11 meeting in
Salt Lake City?

I've copied the X3J11 list and the NCEG list so that everyone knows about
this issue.

Thanks in advance for your help.

Tom MacDonald
tamacray.com
uunet!cray!tam

============================================================================

    Questions about meaning of "overlapping objects" for library functions.

The description of memcpy in section 4.11.2.1 of the Standard says:

    void *memcpy(void *s1, const void *s2, size_t n);

    The memcpy function copies n characters from the object pointed
    to by s2 into the object pointed to by s1.  If copying takes
    place between objects that overlap, the behavior is undefined.

The definition of the term "object" in section 1.6 is:

    Object -- a region of data storage in the execution environment,
    the contents of which can represent values.  Except for
    bit-fields, objects are composed of contiguous sequences of one
    or more bytes, the number, order, and encoding of which are
    either explicitly specified or implementation-defined.  When
    referenced, an object may be interpreted as having a particular
    type.

Question 1:  Are the objects in the description of memcpy the largest
objects into which the arguments can be construed as pointing?

In particular, is the behavior of the call of memcpy in example 1 defined,
because the arguments point into the disjoint array objects, a[1] and
a[0]?  Or is the behavior undefined because the arguments both point into
the same array object, a?

    Example 1:  Memcpy between rows of a matrix

    void f1(void) {
            extern char a[2][N];
            memcpy(a[1], a[0], N);
    }

Question 2:  For the purposes of the description of memcpy, can a
contiguous sequence of elements within an array be regarded as an object
in its own right?  If so, are the objects in the description of memcpy the
smallest contiguous sequences of bytes that can be construed as the objects
into which the arguments point?

In example 2, can each of the first and last half of array b be regarded
as an object in its own right, so that the behavior of the call of memcpy
is defined?  (Although they are not declared as separate objects, each
half does seem to satisfy the definition of object quoted above.)  Or is
the behavior undefined, since both arguments point into the same array
object, b?

    Example 2:  Memcpy between halves of an array

    void f2(void) {
            extern char b[2*N];
            memcpy(b+N, b, N);
    }

In example 3, the types of the objects are inferred from the pointers,
and the underlying storage is dynamically allocated.  Is the behavior
of each call of memcpy defined?

    Example 3:  Memcpy within storage from malloc

    void f3(void) {
        void *p = malloc(2*N); /* Allocates an object. */
        {
            char (*q)[N] = p;  /* The object pointed to by p may
				  be interpreted as having type
				  (char [2][N]) when referenced
				  through q. */
            /* ... */
            memcpy(q[1], q[0], N);
            /* ... */
        }
        {
            char *r = p;       /* The object pointed to by p may
				  be interpreted as having type
				  (char [2*N]) when referenced
				  through r. */
            /* ... */
            memcpy(r+N, r, N);
            /* ... */
        }
    }

Since the relationship between the values of the arguments presented to
memcpy is the same in all the above calls, it seems reasonable to expect
that either all these calls of memcpy give defined behavior, or none do.
But which is it?

Similar questions arise for the other library string handling functions
that have undefined behavior when copying between overlapping objects.
These include strcpy, strncpy, strcat, strncat, strxfrm, mbstowcs,
wcstombs, strftime, vsprintf, sscanf, and sprintf.  For these functions,
however, the number of bytes referenced through each pointer depends, at
least in part, upon the values stored in the bytes.

Question 3:  Consider a library function for which the number of bytes
accessed or modified is affected by the values of the bytes.  Is the
object associated with each of its pointer arguments the smallest
contiguous sequence of bytes actually accessed or modified through that
pointer?

In example 4, is the behavior defined if N > strlen(b)?

    Example 4:  Strcpy between halves of an array

    void f4(void) {
            extern char b[2*N];
            strcpy(b+N, b);
    }

In example 5, is the behavior defined if
N > strlen(c) and M > strlen(c) + strlen(c+N)?

    Example 5:  Strcat between portions of an array

    void f5(void) {
            extern char c[N+M];
            strcat(c+N, c);
    }



More information about the Numeric-interest mailing list