7 Replies Latest reply: Aug 14, 2013 3:57 PM by Steve.Clamage-Oracle RSS

    realloc() behavior and C99 compliancy

    sirak564011

      In recent solaris 10 kernel versions (specifically SunOS 5.10 Generic_148888-03), the behavior of realloc() where size is 0 has changed.  I'm told this was done to address C99 compliancy, i'm guessing to change the freeing of existing memory at ptr when size is 0 (C99 requires the memory at ptr be left intact).  The way this was addressed however, has introduced a new non-compliancy.

       

      When reporting this i was referred to: http://docs.oracle.com/cd/E26502_01/html/E29034/realloc-3c.html

      Under 'Description / realloc()': "If size is 0, the space pointed to by ptr is freed and a magic pointer is returned, which is considered as a NULL pointer if passed to free()."

       

      This "magic pointer" is "1" (as in, the address 0x00000001). And if you call realloc(ptrX, 0) for 10 different pointers, you'll get 10 pointers to 0x1 returned.  So, it's able to free the existing memory (as it previously did) and not be uncompliant with C99 since it's supposed to free the memory when returning non-NULL.  However, any non-NULL pointer returned by ANY memory management allocation function must be unique.

       

      Quoting from the same man page link as above, contradictorily, under 'Return Values':

      "If size, nelem, or elsize is 0, either a null pointer or a unique pointer that can be passed to free() is returned."

       

      And from the C99 standard:

      "Each such allocation shall yield a pointer to an object disjoint from any object"

       

      I've reported this, but 'engineering' insists this is expected behavior required by C99.  Can anyone here confirm that there is a compliancy issue, or point out anything in the C99 standard which justifies this behavior?

        • 1. Re: realloc() behavior and C99 compliancy
          marc1842fr

          Yes, that does sound wrong.

          "An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant."

          "Each such allocation shall yield a pointer to an object disjoint from any other object."

           

          "If the size of the space requested is zero, the behavior is implementation-defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object."

           

          So the implementation has 2 choices: return a null pointer (i.e. (void*)0, not just something that 'free' thinks looks like 0, you need to be able to test for ptr==0) or return a unique pointer (hence not a constant).

          • 2. Re: realloc() behavior and C99 compliancy
            Steve.Clamage-Oracle

            marc1842fr wrote:

            ...

             

            So the implementation has 2 choices: return a null pointer (i.e. (void*)0, not just something that 'free' thinks looks like 0, you need to be able to test for ptr==0) or return a unique pointer (hence not a constant).

            That last part the analysis is not quite right. The word "unique" does not appear in that section (7.20.3) of the standard. A non-null return from realloc(ptr,0) does not point to an object. I don't see where the Solaris implementation violates any rule. That is, if the return values from two differentsuch calls do not point to objects, what conclusion could you draw if they compare equal (or not equal)?

             

            I think the Solaris man page for realloc needs some updating, however. It incorrectly says the return values are unique. Bug 17058989.covers some realloc issues.

            • 3. Re: realloc() behavior and C99 compliancy
              marc1842fr

              (sorry for not quoting properly, the editor is too painful)

              7.20.3 may not have the word unique, but it has the expression "an object distinct from any other object", that's pretty close. A non-null return does point to an object, you are just not allowed to access it. If two such values compare equal (and a few extra conditions like no call to free for instance), you should be able to draw the conclusion that they came from the same call to malloc/realloc.

               

              Ok, I'm not a pro in standard wording, so I may be wrong, but I've heard a similar interpretation before and several systems implement it that way. Now I don't really care, so I'll let the OP explain his use case

              • 4. Re: realloc() behavior and C99 compliancy
                sirak564011

                Steve_Clamage wrote:

                That last part the analysis is not quite right. The word "unique" does not appear in that section (7.20.3) of the standard. A non-null return from realloc(ptr,0) does not point to an object. I don't see where the Solaris implementation violates any rule. That is, if the return values from two differentsuch calls do not point to objects, what conclusion could you draw if they compare equal (or not equal)?

                 

                C99 doesn't use the word unique, but there's two statements in 7.20.3 which require any non-null return pointer to be unique.

                "Each such allocation shall yield a pointer to an object disjoint from any other object"

                Meaning no two objects can overlap, or, no address can belong to more than one object.

                "...either a null pointer is returned, or the behavior is as if the size were some nonzero value...".

                This pretty much says if you're not returning null for size 0 then you must treat a 0 and non-zero size the same way; in other words, you cannot have a special case (behavior-wise) when size is '0'.

                • 5. Re: realloc() behavior and C99 compliancy
                  Steve.Clamage-Oracle

                  marc1842fr wrote:

                  ...

                  A non-null return does point to an object, you are just not allowed to access it. If two such values compare equal (and a few extra conditions like no call to free for instance), you should be able to draw the conclusion that they came from the same call to malloc/realloc.

                   

                  ... I've heard a similar interpretation before and several systems implement it that way. Now I don't really care, so I'll let the OP explain his use case

                  You cannot use the pointer returned from realloc() to access an object, so it seems to me it is rather a stretch to call it an allocated object. By the as-if rule, the implementation need not allocate any space at that address (or anywhere else), since no conforming program could tell the difference. The only requirement is that passing that pointer value to free() is safe, which is the case in the Solaris implementation.

                   

                  Since you don't have an object (in any meaningful sense), what would it mean to say whether pointers p1 and p2 point to the same non-object? By analogy with NaN (not-a-number in floating-point arithmetic), I could argue that p1==p2 and p1!=p2 are both false.   The value of a pointer has a meaning only if it points to an object or is a null pointer. The values of p1 and p2 do not have meaning.

                   

                  Other implementations might return unique pointers; that is certainly allowed by the standard.

                  • 6. Re: realloc() behavior and C99 compliancy
                    sirak564011

                    Steve_Clamage wrote:

                     

                    You cannot use the pointer returned from realloc() to access an object...

                    You cannot dereference the returned pointer for the same reason you can't do "int *p = (int *)malloc(sizeof(int))" and dereference "(p + 1)", you're accessing memory beyond what you had allocated.  There's no additional or special rule being stated with "the returned pointer shall not be used to access an object", it's just providing clarity (as in, "just because you've been returned a non-null pointer doesn't mean you can dereference it").  And it's certainly not giving an implementation permission to return anything it wants just because it won't be dereferenced.  It doesn't say it "cannot be used", it says it "cannot be used to access an object", meaning you're free to compare it's value (the address it points to) to another pointer you have and determine if they point to the same object.  The solaris implementation breaks this; you can have two pointers, each of which was acquired through separate, successful (returned non-null) allocations - and they are both equal to the same address ("1").

                     

                    ...so it seems to me it is rather a stretch to call it an allocated object.

                    Since you don't have an object (in any meaningful sense), what would it mean to say whether pointers p1 and p2 point to the same non-object?

                     

                    A pointer to an allocated object is the only thing the standard allows to be returned, besides null.  Read the description:

                     

                    7.20.3.4

                    Returns

                    (4) The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

                     

                    If the 'magic pointer' is not supposed to be a pointer to an object then you shouldn't be returning it.  If it is then you can't return it multiple times because of 7.20.3; "Each such allocation [that's successful and returns non-null] shall yield a pointer to an object disjoint from any other object."


                    If you or your implementation don't believe in objects of 0 size that's fine, return an object of whatever minimum size your implementation uses.  And if you don't want to do that either, the standard still gives you the option of returning NULL.


                     

                    Other implementations might return unique pointers; that is certainly allowed by the standard.

                    Might?  Any other implementations are returning either a unique pointer or NULL.  If anyone doesn't believe that, go try and find one.

                     

                    All standard interpreting aside, the C89 standard used the phrase 'unique pointer' specifically.  C99 reworded it, making it more generic ("...as if size were some nonzero value...").  Does anyone think it likely that C99 would loosen the restriction on what can be returned for 0 size allocations?  For no reason?

                    • 7. Re: realloc() behavior and C99 compliancy
                      Steve.Clamage-Oracle

                      What is the use-case for the original question? Obviously we can create a toy program whose behavior depends on whether realloc(ptr,0) returns different non-zero values each time. (Call realloc for two different allocated pointers and see whether the results are the same and non-zero.) But is this just a distinction without a difference?

                       

                      If you can show a reasonable program having defined behavior that gives incorrect results with the Solaris version of realloc, I'm sure the Solaris engineers would reconsider.