realloc zero bytes?

R

Robert Seacord

The C standard doesn't say anything about what happens when you call
realloc with a size argument of 0. Both glibc and openbsd appear to
return a valid pointer to a zero-sized object.. e.g. the return of a
malloc(0).

Does anyone know of a runtime where realloc() free'ed the object and
then returned NULL? If so, it would make the following idiom for
realloc() exploitable. Here's the idiom, snagged from an openbsd man page:

if ((p2 = realloc(p, nsize)) == NULL) {
if (p)
free(p);
p = NULL;
return NULL;
}
p = p2;

You can see that if nsize is 0 and realloc() free'ed the memory and
returned NULL, it would be a double-free of p.

Thanks,
rCs
 
N

Nelu

Robert Seacord said:
The C standard doesn't say anything about what happens when you call
realloc with a size argument of 0. Both glibc and openbsd appear to
return a valid pointer to a zero-sized object.. e.g. the return of a
malloc(0).

Does anyone know of a runtime where realloc() free'ed the object and
then returned NULL? If so, it would make the following idiom for
realloc() exploitable. Here's the idiom, snagged from an openbsd man page:

The standard (C99) says:
7.20.3.4-3
"... If memory for the new object cannot be allocated, the old object is
not deallocated and its value is unchanged.".
Also:
7.20.3.4-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 ((p2 = realloc(p, nsize)) == NULL) {
if (p)
free(p);

If realloc fails then p retains its old value. If p is NULL when you
pass it to realloc you already know it's NULL and you don't want to free
it.
p = NULL;
return NULL;
}
p = p2;

You can see that if nsize is 0 and realloc() free'ed the memory and
returned NULL, it would be a double-free of p.

Realloc won't free the memory and return NULL because the standard says
it doesn't.
 
I

Ian Collins

Nelu said:
The standard (C99) says:
7.20.3.4-3
"... If memory for the new object cannot be allocated, the old object is
not deallocated and its value is unchanged.".
Also:
7.20.3.4-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."
But if size is 0, there won't be any problems allocating he memory, so
nothing will be allocated and the existing memory will be freed.
Realloc won't free the memory and return NULL because the standard says
it doesn't.
Surely it may free the memory and return a pointer to a zero sized block.
 
N

Nelu

Ian Collins said:
But if size is 0, there won't be any problems allocating he memory, so
nothing will be allocated and the existing memory will be freed.

And it will return a valid pointer that will not be NULL and p2==NULL
will be false.
Surely it may free the memory and return a pointer to a zero sized block.

A valid pointer that's not NULL.
 
B

Barry Schwarz

The C standard doesn't say anything about what happens when you call
realloc with a size argument of 0. Both glibc and openbsd appear to
return a valid pointer to a zero-sized object.. e.g. the return of a
malloc(0).

Of course it does. In n1124 7.20.3, which discusses all three
allocation functions, it says "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.
Does anyone know of a runtime where realloc() free'ed the object and
then returned NULL? If so, it would make the following idiom for
realloc() exploitable. Here's the idiom, snagged from an openbsd man page:

if ((p2 = realloc(p, nsize)) == NULL) {
if (p)
free(p);
p = NULL;
return NULL;
}
p = p2;

You can see that if nsize is 0 and realloc() free'ed the memory and
returned NULL, it would be a double-free of p.

If you add a test for nsize, you can make it safe regardless of the
return value.


Remove del for email
 
K

Kenneth Brody

Barry said:
Of course it does. In n1124 7.20.3, which discusses all three
allocation functions, it says "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.

What happens on an implementation in which malloc(0) returns NULL,
and you pass realloc() zero for the length? Is realloc() allowed
to return NULL?

The source to the runtime library I have here has this note:
* Special ANSI Requirements:
*
* (1) realloc(NULL, newsize) is equivalent to malloc(newsize)
*
* (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
* NULL is returned)
*
* (3) if the realloc() fails, the object pointed to by pblock is left
* unchanged

Is (2) correct? Does ANSI require that the block be free()d and
that NULL be returned?

[...]

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
H

Hallvard B Furuseth

Kenneth said:
The source to the runtime library I have here has this note:
Yes...

C89 4.10.3.4 says "If size is zero and ptr is not a null pointer, the
object it points to is freed." The clause has been deleted from C99.

Yes.
 
K

Kenneth Brody

Hallvard said:
Kenneth said:
The source to the runtime library I have here has this note:
* Special ANSI Requirements: [...]
* (2) realloc(pblock, 0) is equivalent to free(pblock) (except that
* NULL is returned)

C89 4.10.3.4 says "If size is zero and ptr is not a null pointer, the
object it points to is freed." The clause has been deleted from C99.

But what about returning NULL? In all other cases, a NULL return
from realloc() means that the original pointer has not been freed.

[...]

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
H

Hallvard B Furuseth

Crossposting a comp.lang.c thread to comp.std.c:

If realloc(nonnull, 0) returns NULL, has the object been freed?

Or, before this thread explodes: Is there already a definite answer
in a DR or some other thread?

Google found me plenty of threads about "does it return NULL?", and
some which touched the above question too, but I didn't find a clear
answer. Nor did I find a DR about it, but I don't know where to find
a list of all C99 DRs either.

Extracts from C99:

7.20.3 (Memory management functions):
1 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.

7.20.3.4 (The realloc function):
2 The realloc function deallocates the old object pointed to by
ptr and returns a pointer to a new object that has the size
specified by size. (...)

The implementation may return NULL when size=0. The above implies
that if it does, realloc(nonnull, 0) frees the object first.

3 If memory for the new object cannot be allocated, the old object
is not deallocated and its value is unchanged.

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.

The implementation may try to return a non-NULL object. The above
implies that if it does, a NULL return comes from a realloc failure
and the object has not been freed.

C89 4.10.3.4 (or at least my draft of it) said realloc(nonnull, 0)
freed the object, but this sentence has been removed from C99.
 
R

Richard Tobin

Hallvard B Furuseth said:
The implementation may return NULL when size=0. The above implies
that if it does, realloc(nonnull, 0) frees the object first. ....
The implementation may try to return a non-NULL object. The above
implies that if it does, a NULL return comes from a realloc failure
and the object has not been freed.

The question is surely whether, on a system that returns NULL for
malloc(0), a realloc(nonnull, 0) may *fail*, in which case it must
return NULL and not free the memory. This seems allowable but
perverse, since how can the system fail in such a case?

-- Richard
 
J

Joe Wright

Richard said:
The question is surely whether, on a system that returns NULL for
malloc(0), a realloc(nonnull, 0) may *fail*, in which case it must
return NULL and not free the memory. This seems allowable but
perverse, since how can the system fail in such a case?

The case for malloc(0) is unique and looks like realloc(NULL, 0). In my
view, malloc(0) should return NULL. It makes no sense to return a
pointer to zero bytes of storage. There is no case for
realloc(nonnull,0) to fail. free() does not have a failure mode.
 
H

Hallvard B Furuseth

The question is surely whether, on a system that returns NULL for
malloc(0), a realloc(nonnull, 0) may *fail*,

No. If realloc(nonnull, 0) attempts to return non-NULL, presumably
malloc(0) attemts the same - though I don't see that the standard
requires that.
 
A

ais523

(snip; although there are extra >s in the row before, there doesn't
seem to be an attribution line for them)
C89 4.10.3.4 says "If size is zero and ptr is not a null pointer, the
object it points to is freed." The clause has been deleted from C99.
In the context of C89/C90, what is the return value of
realloc(nonnull,0) and of realloc(0,0)? I've seen too many incorrect
compiler manuals to know truth from fiction about this, so I'd
appreciate C&V.
 
R

Richard Tobin

The question is surely whether, on a system that returns NULL for
malloc(0), a realloc(nonnull, 0) may *fail*,
[/QUOTE]
No. If realloc(nonnull, 0) attempts to return non-NULL, presumably
malloc(0) attemts the same - though I don't see that the standard
requires that.

I was considering the case where both malloc() and realloc() return
NULL for zero bytes, but where - somehow - realloc(nonnull, 0) could
fail. In that case, realloc(nonnull, 0) would return NULL both
when it fails and succeeds, but when it fails the memory would not
have been freed.

Obviously it's absurd for realloc() to fail in that case, but I don't
know that the standard prohibits it.

-- Richard
 
H

Hallvard B Furuseth

I was considering the case where both malloc() and realloc() return
NULL for zero bytes, but where - somehow - realloc(nonnull, 0) could
fail.

Yes, and that is _not_ what I was asking about. What I'm talking about
is: When realloc(nonnull, 0) has returned NULL, can the caller know
whether or not the object has been freed - when the caller doesn't know
whether or not the implementation always returns NULL from
realloc(nonnull, 0) (and malloc(0))?
 
R

Richard Tobin

Hallvard B Furuseth said:
Yes, and that is _not_ what I was asking about. What I'm talking about
is: When realloc(nonnull, 0) has returned NULL, can the caller know
whether or not the object has been freed - when the caller doesn't know
whether or not the implementation always returns NULL from
realloc(nonnull, 0) (and malloc(0))?

No. But again a good implementation would never fail for a realloc of
zero bytes: even if it would normally try to allocate a small block,
it can always succeed by returning the original nonnull value.

-- Richard
 
R

Robert Seacord

I think I can answer my own question now:
Does anyone know of a runtime where realloc() free'ed the object and
then returned NULL?

The following code:

char *p2;
char *p = malloc(100);
size_t nsize = 0;

if ((p2 = realloc(p, nsize)) == NULL) {
if (p) free(p);
p = NULL;
return NULL;
}
p = p2;

Compiled with Visual Studio Version 7, blows up on the call to free().

This is because realloc() returns NULL, suggesting that the realloc()
failed and the memory needs to be freed (but presumably already has).

As far as I can tell, this behavior is allowed by the standard.

I tried to write this up as the second example of MEM36-C at:

https://www.securecoding.cert.org/c...ptions+about+the+result+of+allocating+0+bytes

I listed the following code as a compliant solution:

char *p2;
char *p = malloc(100);
....
if ( (nsize == 0) || (p2 = realloc(p, nsize)) == NULL) {
if (p) free(p);
p = NULL;
return NULL;
}
p = p2;

Please let me know if any of this is incorrect.

rCs
 
H

Hallvard B Furuseth

ais523 said:
In the context of C89/C90, what is the return value of
realloc(nonnull,0)

NULL. The object is freed.
Last quoted sentence before Returns (only applies when arg!=NULL).
and of realloc(0,0)?

NULL or a new object.
First quoted sentence in 4.10.3.4, plus 4.10.3.
I've seen too many incorrect compiler manuals to know truth from
fiction about this, so I'd appreciate C&V.

ANSI C (equivalent to C89):

4.10.3 (Memory management functions):

If the size of the space requested is zero, the behavior is
implementation-defined; the value returned shall be either a null
pointer or a unique pointer.

4.10.3.4 (The realloc function):

If ptr is a null pointer, the realloc function behaves like the
malloc function for the specified size. (...) If the space cannot
be allocated, the object pointed to by ptr is unchanged. If size is
zero and ptr is not a null pointer, the object it points to is freed.

Returns
The realloc function returns either a null pointer or a pointer to
the possibly moved allocated space.
 
C

CBFalconer

Hallvard said:
NULL. The object is freed.
Last quoted sentence before Returns (only applies when arg!=NULL).


NULL or a new object.
First quoted sentence in 4.10.3.4, plus 4.10.3.


ANSI C (equivalent to C89):

4.10.3 (Memory management functions):

If the size of the space requested is zero, the behavior is
implementation-defined; the value returned shall be either a
null pointer or a unique pointer.

4.10.3.4 (The realloc function):

If ptr is a null pointer, the realloc function behaves like
the malloc function for the specified size. (...) If the
space cannot be allocated, the object pointed to by ptr is
unchanged. If size is zero and ptr is not a null pointer,
the object it points to is freed.

Returns
The realloc function returns either a null pointer or a
pointer to the possibly moved allocated space.

Which means that proper use of the realloc function, with:

if (tmp = realloc(p, size)) p = tmp;
else {
/* failure, take corrective action */
}

will fall into corrective action for a size of 0, and leave an
invalid value of p hanging about, which may well go BOOM on
eventual use (including free). Thus good implementations will not
return NULL for successful malloc/realloc/calloc of zero sizes.
 
D

Douglas A. Gwyn

Hallvard B Furuseth said:
If realloc(nonnull, 0) returns NULL, has the object been freed?

No. realloc returns a null pointer (only) if the new object could
not be allocated, and if memory for the new object cannot be
allocated, the old objct is not deallocated and its value is unchanged.
Thats directly from the realloc spec (C99 7.20.3.4).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top