Greetings all,
I have a program that used the realloc() function to change the
allocated size of a buffer, the program works with some arguments, but
with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 ***
and then I inserted a perror("realloc") to see what happend, it says that:
realloc: Illegal seek
the realloc() is in a loop:
for (m = 0; m < len; m++) {
if (isspace(data[m]) || ispunct(data[m]) ||
isdigit(data[m]))
printf("%c", data[m]);
else {
p = min(strcspn(&data[m], " "),
strcspn(&data[m], "\t"),
strcspn(&data[m], "\r"),
strcspn(&data[m], "\n"));
key = realloc(key, p);
strncpy(key, &data[m], p);
key[p] = '\0';
trans(key, p);
m = m + p - 1;
}
}
and the "key" is already malloced before the loop:
char *key = malloc(1);
Any suggestion could be helpful, thx very much!
Deephay 27 31219
Deephay <tu*****@gmail.com> wrote: I have a program that used the realloc() function to change the allocated size of a buffer, the program works with some arguments, but with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 ***
and then I inserted a perror("realloc") to see what happend, it says that:
realloc: Illegal seek the realloc() is in a loop:
for (m = 0; m < len; m++) { if (isspace(data[m]) || ispunct(data[m]) || isdigit(data[m])) printf("%c", data[m]); else { p = min(strcspn(&data[m], " "), strcspn(&data[m], "\t"), strcspn(&data[m], "\r"), strcspn(&data[m], "\n"));
Why not simply use strcspn(&data[m], " \t\r\n")?
key = realloc(key, p); strncpy(key, &data[m], p); key[p] = '\0'; trans(key, p); m = m + p - 1; } }
and the "key" is already malloced before the loop:
char *key = malloc(1);
Hard to say what the real problem is without any object or function
definitions, but two questions spring to mind:
- does this occur immediately, or after a few iterations;
- what actually is the value of p (and if this code isn't complete, of
key) at the point where it produces the error?
Richard
Richard Bos wrote: Deephay <tu*****@gmail.com> wrote:
I have a program that used the realloc() function to change the allocated size of a buffer, the program works with some arguments, but with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 ***
and then I inserted a perror("realloc") to see what happend, it says that:
realloc: Illegal seek the realloc() is in a loop:
for (m = 0; m < len; m++) { if (isspace(data[m]) || ispunct(data[m]) || isdigit(data[m])) printf("%c", data[m]); else { p = min(strcspn(&data[m], " "), strcspn(&data[m], "\t"), strcspn(&data[m], "\r"), strcspn(&data[m], "\n")); Why not simply use strcspn(&data[m], " \t\r\n")?
I have to get the index where the first "space" locates. key = realloc(key, p); strncpy(key, &data[m], p); key[p] = '\0'; trans(key, p); m = m + p - 1; } }
and the "key" is already malloced before the loop:
char *key = malloc(1); Hard to say what the real problem is without any object or function definitions, but two questions spring to mind: - does this occur immediately, or after a few iterations; - what actually is the value of p (and if this code isn't complete, of key) at the point where it produces the error?
the error occurred after a few iterations, the first realloc will always
success.
the p is always larger than 0, I have tested. Actually it will be a
quite normal
value where the error produced, say, 7, 8, or whatever...
What I think now is that it might be a bug of glibc...
I searched with google and found some unsolved problem like the one I have.
What I did now is, declare a key[50] static, this works fine.
I still want to make sure what the problem is, though. Richard
Thanks!
Deephay
Deephay wrote: Richard Bos wrote: Deephay <tu*****@gmail.com> wrote:
I have a program that used the realloc() function to change the allocated size of a buffer, the program works with some arguments, but with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 ***
Why not simply use strcspn(&data[m], " \t\r\n")? I have to get the index where the first "space" locates.
Ok, that would be "strcspn(&data[m], " \t\r\n")+1" if there are
any spaces, but you did not add 1 in your code either.
key = realloc(key, p); strncpy(key, &data[m], p); key[p] = '\0'; I still want to make sure what the problem is, though.
The last assignment above invokes undefined behavior even if
realloc() did not return NULL.
Ralf
In article <e1***********@news3.infoave.net>, Deephay <tu*****@gmail.com> writes: I have a program that used the realloc() function to change the allocated size of a buffer, the program works with some arguments, but with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 ***
glibc is off-topic for comp.lang.c, but this is glibc telling you
that you have invoked Undefined Behavior. Probably you have
corrupted glibc's housekeeping data by performing an illegal
operation on an object with dynamic storage duration, such as writing
past the end of an allocated area.
and then I inserted a perror("realloc") to see what happend, it says that:
What will happen is that you will get a meaningless message written
to stderr. realloc does not set errno, so perror will report whatever
happens to have already been in errno.
the realloc() is in a loop:
for (m = 0; m < len; m++) { if (isspace(data[m]) || ispunct(data[m]) || isdigit(data[m])) printf("%c", data[m]); else { p = min(strcspn(&data[m], " "), strcspn(&data[m], "\t"), strcspn(&data[m], "\r"), strcspn(&data[m], "\n")); key = realloc(key, p);
Wrong for two reasons. You failed to check whether realloc
succeeded, and if it failed, you just lost the old value of "key"
and so introduced a memory leak.
The result of realloc should always be stored in a temporary
variable and should be checked for null. If it is null, remember
to free the old value:
char *newkey;
newkey = realloc(key, p);
if (! newkey)
{
free(key);
[perform error handling]
}
key = newkey;
strncpy(key, &data[m], p); key[p] = '\0';
You just wrote past the end of the allocated area. Since key is an
area of p bytes, valid indices are 0 through p-1, inclusive.
and the "key" is already malloced before the loop:
char *key = malloc(1);
Did you check to see whether malloc succeeded?
Any suggestion could be helpful, thx very much!
Read the comp.lang.c FAQ ( http://www.c-faq.com is one source). Get a
copy of the C standard. C makes little effort to protect you from
yourself; you will only produce reliable, correct C code by learning
the language and its pitfalls.
--
Michael Wojcik mi************@microfocus.com
The lecturer was detailing a proof on the blackboard. He started to say,
"From the above it is obvious that ...". Then he stepped back and thought
deeply for a while. Then he left the room. We waited. Five minutes
later he returned smiling and said, "Yes, it is obvious", and continued
to outline the proof. -- John O'Gorman
Deephay <tu*****@gmail.com> wrote: Richard Bos wrote: Deephay <tu*****@gmail.com> wrote:
p = min(strcspn(&data[m], " "), strcspn(&data[m], "\t"), strcspn(&data[m], "\r"), strcspn(&data[m], "\n")); Why not simply use strcspn(&data[m], " \t\r\n")? I have to get the index where the first "space" locates.
That one call does the same thing as those four calls plus a properly
written min() function. key = realloc(key, p); strncpy(key, &data[m], p); key[p] = '\0'; trans(key, p); m = m + p - 1;
and the "key" is already malloced before the loop:
char *key = malloc(1);
Hard to say what the real problem is without any object or function definitions, but two questions spring to mind: - does this occur immediately, or after a few iterations; - what actually is the value of p (and if this code isn't complete, of key) at the point where it produces the error?
the error occurred after a few iterations, the first realloc will always success. the p is always larger than 0, I have tested. Actually it will be a quite normal value where the error produced, say, 7, 8, or whatever...
What I think now is that it might be a bug of glibc...
That is the last thing I would consider.
I searched with google and found some unsolved problem like the one I have.
You can find a great many confused bug-writers on the 'web, yes, many of
them blaming their tools for their own mistakes.
What I did now is, declare a key[50] static, this works fine.
It probably works around a bug - using strncpy() without thorough
understanding is asking for one, btw - and leaves a time bomb in your
code. What happens if you encounter a token larger than 50 characters?
Worse, what if you encounter one of _precisely_ 50 characters?
I still want to make sure what the problem is, though.
Without more code which demonstrates the problem precisely, it is
impossible to be certain. If the above is your exact code, you have
several off-by-one errors; then again, if the above is your exact code,
it doesn't compile, because there is a lot missing.
If you want more help, what you should do now is the following:
- make a copy of your existing code;
- whittle it down to the smallest _compilable_ program which still
exhibits the same problem;
- post _exactly_ that code. Paste, do not retype it into your post,
otherwise you'll make typos.
Richard
Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value:
char *newkey; newkey = realloc(key, p); if (! newkey) { free(key); [perform error handling] } key = newkey;
Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself
if there's a need for that? Also suppose the reallocated memory doesn't
'move' (newkey == key); doing a "free(key);" now could be disastrous.
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
>Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value ...
In article <sl*******************@ID-203069.user.individual.net>
Pedro Graca <he****@hotpop.com> wrote:Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that?
No!
With a few exceptions (noted below), realloc() is essentially an
optimized version of the following:
void *realloc(void *old, size_t newsize) {
size_t oldsize = __some_sort_of_magic_done_here(old);
void *new;
new = malloc(newsize);
if (new != NULL) {
memcpy(new, old, oldsize < newsize ? oldsize : newsize);
free(old);
}
return new;
}
(where the "magic" function obtains the size previously malloc()ed,
or the size of the previously malloc()ed region, whichever is
larger, based on "old", or returns 0 if old==NULL).
Note specifically that "old" is *not*, I repeat NOT, free()d if
"new" memory is not obtainable.
Also suppose the reallocated memory doesn't 'move' (newkey == key);
In this case, the return value from realloc() is necessarily not
NULL (well, except if old==NULL).
In both C89 and C99, realloc(p, 0) (where p!=NULL) is equivalent
to free(p). In at least C89 (and perhaps both C89 and C99),
realloc(NULL, 0) does something no one can quite explain. :-)
(Seriously: C89 specifically said that realloc(NULL,n) was equivalent
to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it
then also said that realloc(p,0) was equivalent to free(p); so what
then is realloc(NULL,0) -- is it like malloc(0) and hence like
malloc(1), or is it just free(NULL)?)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Pedro Graca schrieb: Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value:
char *newkey; newkey = realloc(key, p); if (! newkey) { free(key); [perform error handling] } key = newkey;
Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that? Also suppose the reallocated memory doesn't 'move' (newkey == key); doing a "free(key);" now could be disastrous.
realloc() returns a null-pointer when it fails, hence the if branch is
only taken after a failure in realloc().
Marc Thrun wrote: Pedro Graca schrieb: Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value:
char *newkey; newkey = realloc(key, p); if (! newkey) { free(key); [perform error handling] } key = newkey;
Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that? Also suppose the reallocated memory doesn't 'move' (newkey == key); doing a "free(key);" now could be disastrous.
realloc() returns a null-pointer when it fails, hence the if branch is only taken after a failure in realloc().
Ah! Of course. Thank you.
(sorry Michael)
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Chris Torek wrote: Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value ...
In article <sl*******************@ID-203069.user.individual.net> Pedro Graca <he****@hotpop.com> wrote:Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that?
No!
[snip comprehensive answer]
Thank you very much for the comprehensive answer.
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
"Chris Torek" <no****@torek.net> wrote in message
news:e1********@news2.newsguy.com... Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value ... In article <sl*******************@ID-203069.user.individual.net> Pedro Graca <he****@hotpop.com> wrote:Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that?
No!
With a few exceptions (noted below), realloc() is essentially an optimized version of the following:
void *realloc(void *old, size_t newsize) { size_t oldsize = __some_sort_of_magic_done_here(old); void *new;
new = malloc(newsize); if (new != NULL) { memcpy(new, old, oldsize < newsize ? oldsize : newsize); free(old); } return new; }
Hmm, no NULL check for old?
<snip> (Seriously: C89 specifically said that realloc(NULL,n) was equivalent to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it then also said that realloc(p,0) was equivalent to free(p); so what then is realloc(NULL,0) -- is it like malloc(0) and hence like malloc(1), or is it just free(NULL)?)
If your question wasn't rhetorical, this realloc probably answers your
question. It has undefined behavior since it doesn't determine the 'magic
mystery size' of s1...
void *my_realloc (void *s1, size_t size)
{
void *s2=NULL;
if (size!=0||s1==NULL)
s2 = malloc(size);
else
free(s1);
if (s1!=NULL)
memcpy(s2, s1, size);
return(s2);
}
Rod Pemberton
Michael Wojcik wrote: In article <e1***********@news3.infoave.net>, Deephay <tu*****@gmail.com> writes: I have a program that used the realloc() function to change the allocated size of a buffer, the program works with some arguments, but with some other arguments, it will show me the error message like:
*** glibc detected *** realloc(): invalid next size: 0x0804c3a8 *** glibc is off-topic for comp.lang.c, but this is glibc telling you that you have invoked Undefined Behavior. Probably you have corrupted glibc's housekeeping data by performing an illegal operation on an object with dynamic storage duration, such as writing past the end of an allocated area.
and then I inserted a perror("realloc") to see what happend, it says that:
What will happen is that you will get a meaningless message written to stderr. realloc does not set errno, so perror will report whatever happens to have already been in errno.
the realloc() is in a loop:
for (m = 0; m < len; m++) { if (isspace(data[m]) || ispunct(data[m]) || isdigit(data[m])) printf("%c", data[m]); else { p = min(strcspn(&data[m], " "), strcspn(&data[m], "\t"), strcspn(&data[m], "\r"), strcspn(&data[m], "\n")); key = realloc(key, p);
Wrong for two reasons. You failed to check whether realloc succeeded, and if it failed, you just lost the old value of "key" and so introduced a memory leak.
The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value:
char *newkey; newkey = realloc(key, p); if (! newkey) { free(key); [perform error handling] } key = newkey;
strncpy(key, &data[m], p); key[p] = '\0';
You just wrote past the end of the allocated area. Since key is an area of p bytes, valid indices are 0 through p-1, inclusive.
and the "key" is already malloced before the loop:
char *key = malloc(1);
Did you check to see whether malloc succeeded?
Any suggestion could be helpful, thx very much!
Read the comp.lang.c FAQ (http://www.c-faq.com is one source). Get a copy of the C standard. C makes little effort to protect you from yourself; you will only produce reliable, correct C code by learning the language and its pitfalls.
thx a lot for those suggestions! -- Michael Wojcik mi************@microfocus.com
The lecturer was detailing a proof on the blackboard. He started to say, "From the above it is obvious that ...". Then he stepped back and thought deeply for a while. Then he left the room. We waited. Five minutes later he returned smiling and said, "Yes, it is obvious", and continued to outline the proof. -- John O'Gorman
Richard Bos wrote: Deephay <tu*****@gmail.com> wrote:
Richard Bos wrote: Deephay <tu*****@gmail.com> wrote: p = min(strcspn(&data[m], " "), > strcspn(&data[m], "\t"), > strcspn(&data[m], "\r"), > strcspn(&data[m], "\n"));
Why not simply use strcspn(&data[m], " \t\r\n")? I have to get the index where the first "space" locates.
That one call does the same thing as those four calls plus a properly written min() function.
> key = realloc(key, p); > strncpy(key, &data[m], p); > key[p] = '\0'; > trans(key, p); > m = m + p - 1; and the "key" is already malloced before the loop: > > char *key = malloc(1);
Hard to say what the real problem is without any object or function definitions, but two questions spring to mind: - does this occur immediately, or after a few iterations; - what actually is the value of p (and if this code isn't complete, of key) at the point where it produces the error? the error occurred after a few iterations, the first realloc will always success. the p is always larger than 0, I have tested. Actually it will be a quite normal value where the error produced, say, 7, 8, or whatever...
What I think now is that it might be a bug of glibc...
That is the last thing I would consider.
I searched with google and found some unsolved problem like the one I have.
You can find a great many confused bug-writers on the 'web, yes, many of them blaming their tools for their own mistakes.
What I did now is, declare a key[50] static, this works fine.
It probably works around a bug - using strncpy() without thorough understanding is asking for one, btw - and leaves a time bomb in your code. What happens if you encounter a token larger than 50 characters? Worse, what if you encounter one of _precisely_ 50 characters?
I still want to make sure what the problem is, though.
Without more code which demonstrates the problem precisely, it is impossible to be certain. If the above is your exact code, you have several off-by-one errors; then again, if the above is your exact code, it doesn't compile, because there is a lot missing.
If you want more help, what you should do now is the following: - make a copy of your existing code; - whittle it down to the smallest _compilable_ program which still exhibits the same problem; - post _exactly_ that code. Paste, do not retype it into your post, otherwise you'll make typos.
Richard
thx for the suggestions, Richard, I'll try to exam the code again.
Rod Pemberton wrote: "Chris Torek" <no****@torek.net> wrote in message news:e1********@news2.newsguy.com... (Seriously: C89 specifically said that realloc(NULL,n) was equivalent to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it then also said that realloc(p,0) was equivalent to free(p); so what then is realloc(NULL,0) -- is it like malloc(0) and hence like malloc(1), or is it just free(NULL)?)
If your question wasn't rhetorical, this realloc probably answers your question. It has undefined behavior since it doesn't determine the 'magic mystery size' of s1...
void *my_realloc (void *s1, size_t size) { void *s2=NULL;
if (size!=0||s1==NULL) s2 = malloc(size); else free(s1); if (s1!=NULL) memcpy(s2, s1, size); return(s2); }
Hmm, there seems to be something wrong with this my_realloc():
new_pointer = my_realloc(NULL, 100); /* ok */
new_pointer = my_realloc(NULL, 0); /* ok */
new_pointer = my_realloc(old_pointer, 100); /* old_pointer not free'd */
new_pointer = my_realloc(old_pointer, 0); /* memcpy(NULL, ????, 0); */
In the last example, will the call to memcpy() invoke UB? Or, because
size is 0 (zero), it doesn't matter what the pointers point to?
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
In article <sl*******************@ID-203069.user.individual.net>, Pedro Graca <he****@dodgeit.com> writes: Michael Wojcik wrote: The result of realloc should always be stored in a temporary variable and should be checked for null. If it is null, remember to free the old value:
char *newkey; newkey = realloc(key, p); if (! newkey) { free(key); [perform error handling] } key = newkey;
Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that? Also suppose the reallocated memory doesn't 'move' (newkey == key); doing a "free(key);" now could be disastrous.
The code above only frees key if realloc failed.
--
Michael Wojcik mi************@microfocus.com
"Pedro Graca" <he****@dodgeit.com> wrote in message
news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: "Chris Torek" <no****@torek.net> wrote in message news:e1********@news2.newsguy.com... (Seriously: C89 specifically said that realloc(NULL,n) was equivalent to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it then also said that realloc(p,0) was equivalent to free(p); so what then is realloc(NULL,0) -- is it like malloc(0) and hence like malloc(1), or is it just free(NULL)?) If your question wasn't rhetorical, this realloc probably answers your question. It has undefined behavior since it doesn't determine the
'magic mystery size' of s1...
void *my_realloc (void *s1, size_t size) { void *s2=NULL;
if (size!=0||s1==NULL) s2 = malloc(size); else free(s1); if (s1!=NULL) memcpy(s2, s1, size); return(s2); }
Hmm, there seems to be something wrong with this my_realloc():
new_pointer = my_realloc(NULL, 100); /* ok */ new_pointer = my_realloc(NULL, 0); /* ok */ new_pointer = my_realloc(old_pointer, 100); /* old_pointer not free'd */
That's a simple fix:
if (s1!=NULL)
{
memcpy(s2, s1, size);
free(s1);
}
new_pointer = my_realloc(old_pointer, 0); /* memcpy(NULL, ????, 0); */
You've got that wrong. The last case is memcpy(new_pointer,old_pointer,0);
i.e., new_pointer = my_realloc(old_pointer, 0); /*
memcpy(new_pointer,old_pointer,0); */
If size is zero, s1 is freed (which doesn't set s1 to NULL) and s2 is
returned which is NULL.
In the last example, will the call to memcpy() invoke UB? Or, because size is 0 (zero), it doesn't matter what the pointers point to?
As I said, you've got the last one wrong. No NULL is ever passed to
memcpy(), but a size zero is. To eliminate the size zero problem, you need
to know the old size, and check that it isn't zero. Which as Chris Torek's
example shows, it's based on compiler secrets.
The point of my reply was that Chris Torek's solution will pass NULL's for
'old' that _could_ "invoke" (I really don't like "invoke," it implies a
guaranted action...) UB for the first two situations:
new_pointer = my_realloc(NULL, 100); /* not Ok for ChrisT example*/ new_pointer = my_realloc(NULL, 0); /* not Ok for ChrisT example*/
(If you're keeping score, Chris has two UB, one size zero problem. And,
mine had one coding error, and one size zero problem.)
A closer corrected realloc, would be some merger of mine and Chris', with
zero correction for size:
void *realloc (void *s1, size_t size)
{
void *s2=NULL;
size_t oldsize = __some_sort_of_magic_done_here(old);
if (size!=0||s1==NULL)
s2 = malloc(size);
else
free(s1);
if (s1!=NULL)
{
size=oldsize<size?oldsize:newsize;
if(size==0)
size=1;
memcpy(s2, s1, size);
free(s1);
}
return(s2);
}
HTH,
Rod Pemberton
"Rod Pemberton" <do*********@sorry.bitbuck.cmm> wrote in message
news:e1**********@localhost.localdomain... "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: "Chris Torek" <no****@torek.net> wrote in message news:e1********@news2.newsguy.com... > (Seriously: C89 specifically said that realloc(NULL,n) was equivalent > to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it > then also said that realloc(p,0) was equivalent to free(p); so what > then is realloc(NULL,0) -- is it like malloc(0) and hence like > malloc(1), or is it just free(NULL)?)
If your question wasn't rhetorical, this realloc probably answers your question. It has undefined behavior since it doesn't determine the 'magic mystery size' of s1...
void *my_realloc (void *s1, size_t size) { void *s2=NULL;
if (size!=0||s1==NULL) s2 = malloc(size); else free(s1); if (s1!=NULL) memcpy(s2, s1, size); return(s2); } Hmm, there seems to be something wrong with this my_realloc():
new_pointer = my_realloc(NULL, 100); /* ok */ new_pointer = my_realloc(NULL, 0); /* ok */ new_pointer = my_realloc(old_pointer, 100); /* old_pointer not free'd */
That's a simple fix: if (s1!=NULL) { memcpy(s2, s1, size); free(s1); }
new_pointer = my_realloc(old_pointer, 0); /* memcpy(NULL, ????, 0); */
You've got that wrong. The last case is
memcpy(new_pointer,old_pointer,0); i.e., new_pointer = my_realloc(old_pointer, 0); /* memcpy(new_pointer,old_pointer,0); */
If size is zero, s1 is freed (which doesn't set s1 to NULL) and s2 is returned which is NULL.
In the last example, will the call to memcpy() invoke UB? Or, because size is 0 (zero), it doesn't matter what the pointers point to? As I said, you've got the last one wrong. No NULL is ever passed to memcpy(), but a size zero is. To eliminate the size zero problem, you
need to know the old size, and check that it isn't zero. Which as Chris
Torek's example shows, it's based on compiler secrets.
The point of my reply was that Chris Torek's solution will pass NULL's for 'old' that _could_ "invoke" (I really don't like "invoke," it implies a guaranted action...) UB for the first two situations:
new_pointer = my_realloc(NULL, 100); /* not Ok for ChrisT
example*/ new_pointer = my_realloc(NULL, 0); /* not Ok for ChrisT
example*/ (If you're keeping score, Chris has two UB, one size zero problem. And, mine had one coding error, and one size zero problem.)
A closer corrected realloc, would be some merger of mine and Chris', with zero correction for size:
void *realloc (void *s1, size_t size) { void *s2=NULL; size_t oldsize = __some_sort_of_magic_done_here(old);
if (size!=0||s1==NULL) s2 = malloc(size); else free(s1); if (s1!=NULL) { size=oldsize<size?oldsize:newsize;
Correction:
size=oldsize<size?oldsize:size;
if(size==0) size=1; memcpy(s2, s1, size); free(s1); } return(s2); }
HTH,
Rod Pemberton
Michael Wojcik wrote: In article <sl*******************@ID-203069.user.individual.net>, Pedro Graca <he****@dodgeit.com> writes: Michael Wojcik wrote: > The result of realloc should always be stored in a temporary > variable and should be checked for null. If it is null, remember > to free the old value: > > char *newkey; > newkey = realloc(key, p); > if (! newkey) > { > free(key); > [perform error handling] > } > key = newkey;
Uh? Doesn't realloc(), when it doesn't fail, call free() all by itself if there's a need for that? Also suppose the reallocated memory doesn't 'move' (newkey == key); doing a "free(key);" now could be disastrous.
The code above only frees key if realloc failed.
I think I finally understand why I saw something wrong in that code.
If the reallocation fails and NULL is assigned to newkey, it's supposed
that the "[perform error handling]" doesn't return, so the code will
never get to the "key = newkey;" statement.
I was imagining that the code would go on, and didn't understand the
need to "free(key);" and lose all references to its memory.
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
Rod Pemberton wrote: "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: > void *my_realloc (void *s1, size_t size) > { > void *s2=NULL; > > if (size!=0||s1==NULL) > s2 = malloc(size); > else > free(s1); > if (s1!=NULL) > memcpy(s2, s1, size); free(s1); > return(s2); > } Hmm, there seems to be something wrong with this my_realloc():
new_pointer = my_realloc(NULL, 100); /* ok */ new_pointer = my_realloc(NULL, 0); /* ok */ new_pointer = my_realloc(old_pointer, 100); /* old_pointer not free'd */
That's a simple fix:
[fix incorporated in the code above, check '>' marks] new_pointer = my_realloc(old_pointer, 0); /* memcpy(NULL, ????, 0); */
You've got that wrong. The last case is memcpy(new_pointer,old_pointer,0); i.e., new_pointer = my_realloc(old_pointer, 0); /* memcpy(new_pointer,old_pointer,0); */
If size is zero, s1 is freed (which doesn't set s1 to NULL) and s2 is returned which is NULL.
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 */
if (s1!=NULL)
memcpy(s2, s1, size);
/* And here we go ...
* s2 is NULL, s1 is the free'd valid_old_pointer, size is 0
* so
*
* ...
*
* memcpy(NULL, ????, 0); */
return(s2);
} In the last example, will the call to memcpy() invoke UB? Or, because size is 0 (zero), it doesn't matter what the pointers point to?
As I said, you've got the last one wrong. No NULL is ever passed to memcpy(), but a size zero is.
Where did I go wrong in my step-by-step run of my_realloc()?
To eliminate the size zero problem, you need to know the old size, and check that it isn't zero. Which as Chris Torek's example shows, it's based on compiler secrets.
Yes, I understand this is nothing more than an exercise in second
guessing the compiler secrets ... but I feel it's a good exercise to aid
in developing my knowledge of C.
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
"Pedro Graca" <he****@dodgeit.com> wrote in message
news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net... 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
"Rod Pemberton" <do*********@sorry.bitbuck.cmm> wrote in message
news:e1**********@localhost.localdomain... "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net...
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 ...
Sorry, you're right. _I_ must have been thinking free NULLed ...
RP
"Rod Pemberton" <do*********@sorry.bitbuck.cmm> wrote in message
news:e1**********@localhost.localdomain... "Rod Pemberton" <do*********@sorry.bitbuck.cmm> wrote in message news:e1**********@localhost.localdomain... "Pedro Graca" <he****@dodgeit.com> wrote in message news:sl*******************@ID-203069.user.individual.net... Rod Pemberton wrote: > "Pedro Graca" <he****@dodgeit.com> wrote in message > news:sl*******************@ID-203069.user.individual.net... 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
Rod Pemberton wrote: Rod Pemberton Pedro Graca
[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?
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
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.
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999 http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
>"Chris Torek" <no****@torek.net> wrote in message news:e1********@news2.newsguy.com... With a few exceptions (noted below), realloc() is essentially an optimized version of the following:
void *realloc(void *old, size_t newsize) { size_t oldsize = __some_sort_of_magic_done_here(old); void *new;
new = malloc(newsize); if (new != NULL) { memcpy(new, old, oldsize < newsize ? oldsize : newsize); free(old); } return new; }
In article <e1**********@localhost.localdomain>,
Rod Pemberton <do*********@sorry.bitbuck.cmm> wrote: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.
(Seriously: C89 specifically said that realloc(NULL,n) was equivalent to malloc(n), and malloc(0) *could* be equivalent to malloc(1); it then also said that realloc(p,0) was equivalent to free(p); so what then is realloc(NULL,0) -- is it like malloc(0) and hence like malloc(1), or is it just free(NULL)?)
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.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Rod Pemberton wrote: Pedro, is this one any better?
[snip my_realloc() implementation]
Yes :)
But I'm not the best guy around here to be asked stuff.
--
If you're posting through Google read <http://cfaj.freeshell.org/google>
"Chris Torek" <no****@torek.net> wrote in message
news:e1*********@news1.newsguy.com... "Chris Torek" <no****@torek.net> wrote in message news:e1********@news2.newsguy.com... With a few exceptions (noted below), realloc() is essentially an optimized version of the following: In article <e1**********@localhost.localdomain>, Rod Pemberton <do*********@sorry.bitbuck.cmm> wrote: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.
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Roy |
last post by:
Hi all :
My code below :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *cat(char *s, const char *t)
{
char *tmp;
|
by: James S. Singleton |
last post by:
If we do
q = realloc(p, 128) ;
and on (successful) return of realloc, q != p, must the block pointed to
by p be explicitly freed, or has realloc freed it already?
|
by: James S. Singleton |
last post by:
Thanks everybody for your replies. I gather that:
a) How to obtain the size of the memory region pointed to by ptr in
realloc(ptr, size) is implementation-dependent.
b) Implementing...
|
by: alex323 |
last post by:
Hey. I must have an array that can be resized dynamically. I have coded
an implementation of it using malloc/realloc, but I am getting a
runtime error as seen below in GDB:
*** glibc detected...
|
by: bwaichu |
last post by:
Is it generally better to set-up a buffer (fixed sized array) and read
and write to that
buffer even if it is larger than what is being written to it? Or is it
better to allocate memory and...
|
by: solanki.chandrakant |
last post by:
hi
i have fedora linux 4 and i have simple realloc program which i am
included here... plz help me to overcome the realloc to pointer to
character variable. The program working 2 times but more...
|
by: Robert Seacord |
last post by:
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...
|
by: marvinla |
last post by:
Hello!
I'm a beginner in C, and I'm having trouble with a pointer-to-pointer
reallocation.
This piece of code works well, but Valkyrie warns some parts (pointed
below), and is
breaking my real...
|
by: lancer6238 |
last post by:
Hi,
I'm writing a program that separates a set of integers into groups and
then quicksort each group individually. However, I'm having problems
with my realloc() function. (Pardon me if the...
|
by: DolphinDB |
last post by:
Tired of spending countless mintues downsampling your data? Look no further!
In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
|
by: ryjfgjl |
last post by:
ExcelToDatabase: batch import excel into database automatically...
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM).
In this month's session, we are pleased to welcome back...
|
by: Vimpel783 |
last post by:
Hello!
Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
|
by: CloudSolutions |
last post by:
Introduction:
For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
|
by: Defcon1945 |
last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
|
by: Shællîpôpï 09 |
last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
|
by: af34tf |
last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
|
by: isladogs |
last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM).
In this session, we are pleased to welcome former...
| |