1

There is no reason for realloc()ing to a smaller size will fail. It's freeing up the remainder. I see no reason at all for it to fail. This being said, is it safe to assume that realloc()ing to a smaller size will never fail?

  • 4
    Don't assume anything. Always check for errors. – dbush Jul 07 '20 at 22:27
  • 1
    Indeed, see https://stackoverflow.com/a/1986572/12362709 – Necklondon Jul 07 '20 at 22:28
  • 3
    The C standard does not require `realloc` to succeed if the new size is smaller. We could imagine a memory allocation library built for debugging purposes that deliberately provided new memory for every allocation and that wrote telltale data over each deallocated space, so that erroneous uses of deallocated space would be more likely to be detected. In such a library, `realloc` to a smaller size could fail because there was no new memory available to provide. So, the C standard permits it, and there is potentially a good reason for it to happen. – Eric Postpischil Jul 07 '20 at 22:42
  • 3
    Once you start to make assumptions that something cannot fail, you are on a slippery slope to thinking that you don't need to check things when you can't see a reason for failure. Good practice with C is to make those checks. – Weather Vane Jul 07 '20 at 22:44

5 Answers5

2

"There is no reason for realloc()ing to a smaller size will fail." is an assertion without evidence.

As the spec for the Standard C library does not require a reduction to never fail, robust code would not assume an error is not possible, even if unlikely.


In particular, C17dr spec has Future library directions which discusses reduction to 0.

Invoking realloc with a size argument equal to zero is an obsolescent feature.

I take this to imply now and in the future, the following code which reduces the allocation to 0 should be avoided.

void *p = malloc(42);
...
realloc(p, 0);  // Obsolete
// and instead
free(p);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • @Pound define MACRO : Consider an allocation system with a with a max number of allocations, _handles_ we could call them. For some reason the realloc requires using a new handle before releasing the old. When all handles are used, `realloc()` to any new size fails as the allocation system lacks that temporary one handle needed. The larger point is that C works with many systems and obliging a "no fail" on reduction is simply not an important requirement – chux - Reinstate Monica Jul 08 '20 at 01:54
2

There is no reason for realloc()ing to a smaller size will fail.

Consider an implementation that grabs large blocks from the platform's underlying address space allocator and dices them into small pieces. A realloc that reduces the size of the allocation might require a new block to be allocated if the size requested is not within the range of supported sizes for the large block the block being reallocated came from.

In this case, the implementation will need to get a smaller block from a sub-allocator whose range of serviced sizes includes the size requested. That sub-allocator may not have any free blocks and when it requests a new large block to dice up, that can fail.

So the premise of this question is false.

Also, in general, it is a terrible idea to leap from "I cannot think of any reason this would fail" to "I can assume this will not fail". There are many stories of things that failed for reasons people could not foresee and some of them have horrible consequences.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
1

From the linux manpages:

The realloc() function returns a pointer to the newly allocated memory, which is suitably aligned for any built-in type and may be different from ptr. [...] If realloc() fails, the original block is left untouched; it is not freed or moved.

It cannot be assumed that the block will not be moved because this is implementation-specific. For example, the block could be moved in the case of compactification.

fcdt
  • 2,371
  • 5
  • 14
  • 26
  • Linux manual pages document Linux behaviors, which, while they may conform to requirements of the C standard, may also be more constrained. Thus, Linux documentation may give misleading answers to questions about C and are not a good reference for this purpose. – Eric Postpischil Jul 07 '20 at 22:37
  • The question asks whether `realloc` can fail, but this answer seems to speak to whether the block will or will not be moved, which is a different question. – Eric Postpischil Jul 07 '20 at 22:38
  • @EricPostpischil So better refer on [POSIX defintions](https://pubs.opengroup.org/onlinepubs/009696899/functions/realloc.html)? – fcdt Jul 07 '20 at 22:40
  • 1
    No, for C questions that are not specific to Linux or Posix or a specific operating system, use [the C standard](https://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents). – Eric Postpischil Jul 07 '20 at 22:43
1

For cases where the requested size is smaller than the original and non-zero, one could safely make a copy of the original pointer before calling realloc, and set the pointer back to that value in case the realloc returns null. If the realloc size is zero, things are a bit murky. Some implementations would treat realloc(ptr, 0); as equivalent to free(ptr); return 0;, which would return null after freeing the object, but others would treat it as equivalent to realloc(ptr,1);, which would only return null in cases where the original pointer would still be valid. Unfortunately, there's no general way of knowing which behavior an implementation would use, and thus no way to properly handle a null return from realloc(ptr, 0);.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

TL;DR

No, you cannot assume that.

There is no reason for realloc()ing to a smaller size will fail. It's freeing up the remainder. I see no reason at all for it to fail.

chux covered details about this pretty well. So I answer in a more general way.

The type of reasoning you're using here is a quite dangerous one. Your basic reasoning is "I cannot see why X is true, therefore I assume X is false." Be very careful with reasoning that way.

First, let's skip the very obvious danger that even though you cannot see any reason for realloc failing in this case, that does not mean that you are correct.

Instead let's assume that you are correct. That there is provably no rational reason whatsoever to implement realloc in such a way that it would ever fail is the new size is equal or smaller than the original. Then it's still a faulty argument, because you cannot assume that the programmers who coded the implementation you're using had this knowledge. There was a provably optimal way of doing this, but the coders did not know that.

Also, the very fact that the C standard does NOT say that this is safe is a good indication (however, not a proof) that there are good reasons to not give that guarantee.

If the specifications does not say that it always succeeds during some circumstances, then you should always consider the risk of failure as non-zero. And in this case, the standard does not give any promises, so no you cannot assume that.

Also, in reality there is often the case where it would be relatively easy to implement things in a "good" way, but it will still be more complicated than the simplest way. And sometimes that simplicity is desirable. The easiest way I can think of to implement realloc is something like this:

void *realloc(void *ptr, size_t new_size)
{
    void *ret = malloc(new_size);
    if(ret) {
        memcpy(ret, ptr, new_size);
        free(ptr);
    }
    return ret;
}

One very valid reason of implementing it this way would be that you have a specific environment where you typically never would use realloc and you throw this in for the sole purpose of conforming to the standard. And whenever you do something for the sole purpose of conforming to a standard or specification, you would typically go for simplicity above all else.

klutt
  • 30,332
  • 17
  • 55
  • 95