Does realloc "move" a block it shortens?

F

Francois Grieu

I guess this program has undefined behavior, as far as ISO C
is concerned.

Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)


#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char *CopyStr(const char* s)
{
size_t n;
char *p;
n = strlen(s)+1;
if ((p = malloc(n))==NULL)
exit(EXIT_FAILURE);
memcpy(p,s,n);
return p;
}

void ShortenStr(char* p)
{
size_t n;
n = strlen(p);
p = realloc(p,n); /* could this move p ? */
p[n-1] = '\0';
}

int main(void)
{
char *p;
p = CopyStr("0123456789abcdef");
ShortenStr(p);
/* if realloc moved p, it is invalid */
puts(p);
return(EXIT_SUCCESS);
}


François Grieu
 
A

Afifov

Bonjour Francois, je n'ais pas compris juste que'est ce que tu veus
faire.Tu veus copier le string p, apres annuler les space vide, et le
metre en memoire?
Ci c'est ca, cherche sur google pour la method "*trim".

Been some time since i talked french. Just thought of doing so.

Hope this helps.
Later.
 
C

CBFalconer

Francois said:
I guess this program has undefined behavior, as far as ISO C
is concerned.

Yes, for various reasons.
Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)

So what, when correction is simple.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char *CopyStr(const char* s)
{
size_t n;
char *p;
n = strlen(s)+1;
if ((p = malloc(n))==NULL)
exit(EXIT_FAILURE);
memcpy(p,s,n);
return p;
}

void ShortenStr(char* p)

char *ShortenStr(char *p)
{
size_t n;

char *t;
n = strlen(p);
p = realloc(p,n); /* could this move p ? */

if (t = realloc(p, n+1)) t[n] = '\0';
return t;
p[n-1] = '\0';
}

int main(void)
{
char *p;
p = CopyStr("0123456789abcdef");
ShortenStr(p);

if (p = ShortenStr(p)) {
puts(p);
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
/* if realloc moved p, it is invalid */
puts(p);
return(EXIT_SUCCESS);
}

However they are dangerous routines in that all strings handled
must reside in malloced memory.
 
E

Eric Sosman

Francois said:
I guess this program has undefined behavior, as far as ISO C
is concerned.

Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)

I don't know whether any widely-available realloc()
implementations do this, but two of the implementations
I wrote as replacements for use in a particular program
would do so, under the right circumstances:

- One version *always* moved the data to a new location,
whether it grew, shrunk, or stayed the same size. It also
filled the old region with 0xDEADBEEF. The purpose was to
aid debugging by making it more likely that some kinds of
bugs would generate detectable errors.

- Another version used different memory "pools" for
allocations of different sizes: there was a pool for tiny
objects of <=16 bytes, another for objects whose size was
equal to that of a particular struct (the program used a
large number of instances of this struct), and a fairly
traditional implementation for all other sizes. The idea
was to avoid the usual malloc() overhead for small objects
and for the struct that was created in such huge numbers.
If you started with a 100-byte object, say, and shortened
it to 10 bytes, realloc() would try to move it from the
"everything else" pool to the "tiny" pool.
 
M

Malcolm

Francois Grieu said:
Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)
I've written lazy implementations which just call malloc() followed by
memcpy().
 
J

John Bode

Francois Grieu said:
I guess this program has undefined behavior, as far as ISO C
is concerned.

Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)

AFAIK, there's no restriction on realloc() moving a block that's
shortened (I don't have a copy of the Standard handy, though, so don't
treat that as gospel).
There is a bug in the code below, though, and that may be what's
giving you problems.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

char *CopyStr(const char* s)
{
size_t n;
char *p;
n = strlen(s)+1;
if ((p = malloc(n))==NULL)
exit(EXIT_FAILURE);
memcpy(p,s,n);
return p;
}

void ShortenStr(char* p)

Since *p can potentially be written to if realloc() relocates the
memory, it should be passed by reference, i.e.

void ShortenStr(char **p)
{
size_t n;
n = strlen(p);

n = strlen(*p);
p = realloc(p,n); /* could this move p ? */

*p = realloc (*p,n);
p[n-1] = '\0';

(*p)[n-1] = '\0';
}

int main(void)
{
char *p;
p = CopyStr("0123456789abcdef");
ShortenStr(p);

ShortenStr(&p);
 
C

Christian Bau

Francois Grieu said:
I guess this program has undefined behavior, as far as ISO C
is concerned.

Anyone knows an implementation where realloc actually moves
a block that it shortens (as opposed to grows?)

It is quite possible. There are malloc implementations that try to
suballocate all blocks of size x, 2^k <= x < 2^(k+1), from the same
block. On such an implementation, if you call realloc (malloc (3000),
1500), the block will be reallocated in such an implementation.
 
F

Francois Grieu

I asked

} I've written lazy implementations which just call malloc() followed by
} memcpy().


] There are malloc implementations that try to suballocate all blocks
] of size x, 2^k <= x < 2^(k+1), from the same block.

Thanks, I'm convinced: it can happen.


Thanks for those that jumped to fix my crafted-for-the-purpose-sample code.
My actual problem is that a script compiler I maintain
- mallocs a block for to some maximum size, before knowing the final size
(typically much smaller)
- while parsing and filling the block, keeps the adresse of some
locations in the block that will need later fixing
- resizes the bloc to its final size, with a runtime test that
realloc did not move the block (it never happened so far)
- much later, fixes the references.

François Grieu
 
B

Barry Schwarz

On Sat, 11 Sep 2004 08:58:44 +0200, Francois Grieu

snip
Thanks for those that jumped to fix my crafted-for-the-purpose-sample code.
My actual problem is that a script compiler I maintain
- mallocs a block for to some maximum size, before knowing the final size
(typically much smaller)
- while parsing and filling the block, keeps the adresse of some
locations in the block that will need later fixing
- resizes the bloc to its final size, with a runtime test that
realloc did not move the block (it never happened so far)
- much later, fixes the references.
It might be worthwhile to review the code that fixes the references to
determine if there is any undefined behavior when the block is
relocated. It might be easier to maintain offsets or displacements
which will be invariant regardless or relocation.


<<Remove the del for email>>
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top