1

Is there any way to do this? Properly speaking, I need a portable way, but non-portable one would be useful too. Thanks.

Clarification: I got a buffer that contains zero terminated string (or many strings, as it may be when using strtok) and I need to copy string pointed by an arbitrary pointer (new_string) to that buffer. As far as I don't know actual buffer size (let us say, it's impossible), I need to realloc it (except in the case of strlen(buffer) >= strlen(new_string) - here buffer definitely has enough room to store new_string) and then copy new_string to reallocated buffer. And here's the problem: if new_string points to string somewhere inside buffer, it may become invalid after realloc. So I need to detect this special case and handle it appropriately.

nitrocaster
  • 306
  • 2
  • 15
  • Yea - but it depends on what information you stored when you allocated the block. Some compilers will store size of allocated block just below the pointer but you cannot rely on that behavior - so if you need this you have to do some bookkeeping of your own – Floris May 24 '14 at 20:24
  • It would really help to clarify your question - give an example of what you are trying to do in code. – Floris May 24 '14 at 20:27

2 Answers2

1

Non-portable but likely to work:

if (p >= block_start && p < block_start + block_len)

If the types don't match, you should cast them all to char *.

The reason the above solution is non-portable is that pointer comparisons are not defined except between pointers to elements of the same array. With most real-world compilers they "work" and do what you expect, but there's no requirement that they do, and on segmented architectures or implementations with advanced bounded pointers, etc. they might not.

The portable (but very slow) way is:

for (i=0; i<block_len; i++)
    if (p == blocK_start + i) // pointer points inside the block

Note that for this version to work all the pointers should point to a character type.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
  • The second reason is that there's no portable way to detect block size, afaik. – nitrocaster May 24 '14 at 20:30
  • Note that if `block_len` is in `char` units (i.e. it's the exact value passed to `malloc`), you need to cast to `char *` anyway to make the end calculation correct. Likewise, if `block_len` is in some larger unit (i.e. `malloc` got `block_len * sizeof(something)`), you need to correct that when you cast to `char *` for another reason. –  May 24 '14 at 20:31
  • @nitrocaster Well, keep track of how much you allocated. Takes some discipline, but is fully portable. –  May 24 '14 at 20:32
  • @delnan: Thanks. Yes, it's best to work in `char *` everywhere here. – R.. GitHub STOP HELPING ICE May 24 '14 at 20:33
  • @delhan, no way. I can't modify allocation logic because it's necessary to keep compatibility with pointers returned by standard malloc. – nitrocaster May 24 '14 at 20:34
  • @nitrocaster So you are handed pointers to arbitrary allocated blocks, with no size information? You should edit more information, including what you're actually trying to do, in the question then. –  May 24 '14 at 20:36
  • @nitrocaster: There is no solution if you don't keep track of the size information. Are you trying to implement some kind of garbage collection? If so, just don't. It's not possible in C and you'll make a huge mess of unreliability and randomness. – R.. GitHub STOP HELPING ICE May 24 '14 at 20:46
0

You say that you realloc if strlen(new_string) > strlen(buffer) (although presumably you mean the size of the buffer as it might not exactly contain a string). However, if new_string points into buffer, and new_string is actually a string, then strlen(new_string) cannot possibly be bigger than the buffer size.

So if you find strlen(new_string) > buffer_size then you know it is safe to realloc because new_string can't be in the buffer.

Also, note that it's undefined behaviour to strcpy between two buffers that overlap. (The strcpy function doesn't have to do while (*s++ = *t++); - it could start from the other end , or use some optimized technique that copies chunks, etc.). If you need to support this function copying from one part of the buffer to another, it'd be safer to use memmove plus manually moving the null terminator.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • > _You say that you realloc if strlen(new_string) > strlen(buffer)_ Actually, I always do realloc. It's just a special case when it's not required, but this case can be ignored. > _although presumably you mean the size of the buffer as it might not exactly contain a string_ No, I mean exactly strlen(buffer), because it's impossible to detect buffer size. – nitrocaster May 25 '14 at 06:25
  • > _So if you find strlen(new_string) > buffer_size then you know it is safe to realloc because new_string can't be in the buffer._ You're wrong. Let me show an example: `char *buffer = strdup("foo foobar"), buffer[3] = '\0'; // buffer : "foo"` `char *new_string = buffer+4; // new_string : "foobar"` `my_strcpy(&buffer, new_string); // problem here` – nitrocaster May 25 '14 at 06:26
  • That isn't a problem; the buffer size is 11 and the new string length is 7 (including terminator). If you're trying to determine the existing buffer size using `strlen`, and then doing `realloc`, that's a pretty feeble design. Consider either tracking the actual allocation size, or using `malloc` instead of `realloc`. – M.M May 25 '14 at 07:14
  • > tracking the actual allocation size --- This is library code that should work with standard allocators. ... or using malloc instead of realloc --- performance hit, because realloc is potentially faster then malloc+free. – nitrocaster May 25 '14 at 07:27