realloc(): invalid next size

R

Rod Pemberton

Pedro Graca said:
Right. Let's run "my_realloc(valid_old_pointer, 0);" step by step ...

void *my_realloc (void *s1, size_t size)
{
void *s2=NULL;
/* s1 --> valid_old_pointer
* s2 --> NULL
* size --> 0 */

if (size!=0||s1==NULL)
s2 = malloc(size);
else
free(s1);
/* s1 --> free'd valid_old_pointer
* s2 --> NULL
* size --> 0 */

Correct to here.
if (s1!=NULL)
memcpy(s2, s1, size);
/* And here we go ...

No we don't. s1!=NULL is true. This if() is skipped. s1 is freed, but is
_NOT_ NULL. It retains it's prior value. Why? Because, the argument to
free() is passed by value. That means s1 isn't changed.

free() is declared as:
void free(void *ptr);

For free() to return a NULL as you seem to think, it'd need to be declared
as (this would also change the way it is called):
void free(void **ptr);

HTH,
Rod Pemberton
 
R

Rod Pemberton

Sorry, you're right. _I_ must have been thinking free NULLed ...

Pedro, is this one any better?

void *my_realloc (void *s1, size_t size)
{
void *s2=NULL;

if(size!=0)
s2 = malloc(size);
if(s1!=NULL&&size!=0)
memcpy(s2, s1, size);
if(s1!=NULL)
free(s1);
return(s2);
}


Rod Pemberton
 
P

Pedro Graca

Rod said:
Rod Pemberton
[snip a lot of confusion]

Now that /that/ is taken care of ... -- but I may still come back to it
in a day or two :)


Does this program

#include <stdlib.h>
#include <string.h>
int main(void) {
void * ptr = malloc(42);
if (ptr) {
free(ptr);

memcpy(NULL, ptr, 0);
memcpy(ptr, NULL, 0);
}
return 0;
}

invoke UB at any point?

Or, because the number of bytes "to copy" is 0 (zero) it doesn't matter
what the pointers point to?
 
R

Richard Heathfield

Pedro Graca said:
Does this program

#include <stdlib.h>
#include <string.h>
int main(void) {
void * ptr = malloc(42);
if (ptr) {
free(ptr);

memcpy(NULL, ptr, 0);
memcpy(ptr, NULL, 0);
}
return 0;
}

invoke UB at any point?

Four points.
Or, because the number of bytes "to copy" is 0 (zero) it doesn't matter
what the pointers point to?

It matters. The definition of memcpy requires that the two pointer
parameters each point to an object. NULL does not point to an object (and,
indeed, is *guaranteed* not to point to an object). Furthermore, the value
of ptr is indeterminate, and yet you are evaluating it. This evaluation
takes place *before* memcpy is even called.

Therefore, and for two different reasons, the behaviour is undefined,
irrespective of the number of bytes to be copied.
 
C

Chris Torek

Hmm, no NULL check for old?

I was (admittedly sloppily/non-Standard-ly) omitting it on the
assumption that memcpy(new, NULL, 0) would be a no-op rather than
causing problems. Better to check. Of course, a "real" realloc()
(a) has to supply the "magic" that figures out the old size, and
(b) should (but does not have to) optimize those cases where the
realloc can be done without copying. The intent was really just
to show "minimal required behavior", as it were.
If your question wasn't rhetorical, this realloc probably answers your
question. [code snipped]

Alas, no code can answer the question unless that code comes in
the form of a response to a Defect Report to the C standards people.

The problem is that the text of the Standard is written in a
semi-formal English, leaving some items ambiguous. Sometimes the
ambiguity is intentional, to allow different implementations to do
different things. Sometimes it is, I think at least, just pointless
ambiguity. (The *answer* to my question is not usually very
interesting, though. I tend not to realloc() to size 0 and therefore
not care what it might or might not do.)

(I understand why the Standards folks did not want to use something
more formal -- whether mathematical notation or actual code -- to
define things. I think it was at least occasionally the wrong
decision, though. It would be possible to specify things precisely,
then use English text to relax the requirements, instead of using
English to specify things laxly. That might reduce the flexibility
to implementors, but it could greatly improve the predictability to
users.)
 
R

Rod Pemberton

Chris Torek said:
I was (admittedly sloppily/non-Standard-ly) omitting it on the
assumption that memcpy(new, NULL, 0) would be a no-op rather than
causing problems. Better to check. Of course, a "real" realloc()
(a) has to supply the "magic" that figures out the old size, and
(b) should (but does not have to) optimize those cases where the
realloc can be done without copying. The intent was really just
to show "minimal required behavior", as it were.

That's why I mentioned: "If your question wasn't rhetorical."
Unfortunately, Pedro had to beat me up pretty good to get me to realize I
wasn't reading my code as written, but thinking my code as I thought it
worked when I wrote it... :-(
The problem is that the text of the Standard is written in a
semi-formal English, leaving some items ambiguous. Sometimes the
ambiguity is intentional, to allow different implementations to do
different things. Sometimes it is, I think at least, just pointless
ambiguity. (The *answer* to my question is not usually very
interesting, though. I tend not to realloc() to size 0 and therefore
not care what it might or might not do.)

The problem is that they stripped the historical context and the "C is built
upon assembly language" context that helped define earlier C
implementations. There are things in the C89/90 spec. that I'm sure were
upper boundaries for 16-bit compilers. Unfortunately, people who didn't use
C in the '80s or early 90's usually think they are the lower boundaries.
The spec. of course is sufficiently vauge that they can be upper boundaries
for a 16-bit compiler and lower boundaries for a 32-bit one.
(I understand why the Standards folks did not want to use something
more formal -- whether mathematical notation or actual code -- to
define things. I think it was at least occasionally the wrong
decision, though. It would be possible to specify things precisely,
then use English text to relax the requirements, instead of using
English to specify things laxly. That might reduce the flexibility
to implementors, but it could greatly improve the predictability to
users.)

Even here most people say: "It invokes undefined behavior." "Invokes" to me
implies a guaranteed result. It's closer to "will cause" than "may cause."
Unfortunately or fortunately, almost all cases of UB work as intended and
don't cause any blatantly obvious defect like a crash, lockup, or memory
corruption.


Rod Pemberton
 

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

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top