www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Should GC.realloc(null, N) be the equivalent of GC.calloc or GC.malloc?

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
When called with an existing buffer, GC.realloc conditionally clears the 
newly extended part of the memory. An excerpt from druntime/src/gc/gc.d:

void *realloc(void *p, size_t size, uint bits = 0, size_t *alloc_size = 
null, const TypeInfo ti = null) nothrow
{
     // ...

     if (p !is oldp && !(bits & BlkAttr.NO_SCAN))
     {
         memset(p + size, 0, *alloc_size - size);
     }

     return p;
}

(Disclaimer: Although undocumented, I assume that clearing the memory is 
an intended feature of GC.realloc.)

With that behavior in mind, when called with null, should GC.realloc do 
the same thing to the entirety of the newly allocated memory?

I think it should. Otherwise, the idiom of lazily extending a memory 
buffer with realloc cannot be applied because one needs to memset after 
the first call explicitly:

import core.memory;

void main()
{
     ubyte* p = null;

     // Note that p is null for the first call
     p = cast(ubyte*)GC.realloc(p, 10);
     p = cast(ubyte*)GC.realloc(p, 20);

     // There are non-zero bytes in the first half:
     foreach (i; 0 .. 10) {
         assert(p[i] == 0); // <-- Assertion fails for some i!
     }
}

Ali
Jul 17 2014
parent reply Rainer Schuetze <r.sagitario gmx.de> writes:
On 17.07.2014 23:52, Ali Çehreli wrote:
 When called with an existing buffer, GC.realloc conditionally clears the
 newly extended part of the memory. An excerpt from druntime/src/gc/gc.d:

 void *realloc(void *p, size_t size, uint bits = 0, size_t *alloc_size =
 null, const TypeInfo ti = null) nothrow
 {
      // ...

      if (p !is oldp && !(bits & BlkAttr.NO_SCAN))
      {
          memset(p + size, 0, *alloc_size - size);
      }

      return p;
 }

 (Disclaimer: Although undocumented, I assume that clearing the memory 
 is an intended feature of GC.realloc.)
It clears the memory beyond the requested size. This is usually not accessible to the user (at least if he didn't provide the alloc_size parameter). I believe this is meant to avoid false pointers in the memory range that the user will not fill with other data. It is not meant to mimick calloc.
Jul 17 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/17/2014 03:35 PM, Rainer Schuetze wrote:

 On 17.07.2014 23:52, Ali Çehreli wrote:
 When called with an existing buffer, GC.realloc conditionally clears the
 newly extended part of the memory. An excerpt from druntime/src/gc/gc.d:

 void *realloc(void *p, size_t size, uint bits = 0, size_t *alloc_size =
 null, const TypeInfo ti = null) nothrow
 {
      // ...

      if (p !is oldp && !(bits & BlkAttr.NO_SCAN))
      {
          memset(p + size, 0, *alloc_size - size);
      }

      return p;
 }
> > (Disclaimer: Although undocumented, I assume that clearing the memory > is an intended feature of GC.realloc.) > It clears the memory beyond the requested size. This is usually not accessible to the user (at least if he didn't provide the alloc_size parameter).
Ah! You're right. My brain is not working properly lately. However, this side question that need not be answered remains: If I started with GC.calloc, shouldn't GC.realloc give me memory that is cleared? Or at least don't I deserve a GC.recalloc()? But wait: Do I want to complicate realloc even further? NO! :p Ali
Jul 17 2014
parent "safety0ff" <safety0ff.dev gmail.com> writes:
On Thursday, 17 July 2014 at 23:51:03 UTC, Ali Çehreli wrote:
 However, this side question that need not be answered remains: 
 If I started with GC.calloc, shouldn't GC.realloc give me 
 memory that is cleared?
No, the GC doesn't track whether the memory was calloc'ed.
 Or at least don't I deserve a GC.recalloc()?
The only reasonable way to implement this would be to have calloc always zero the over-allocation. It's also worth noting that there's no reqalloc, so any user implementation of recalloc will have to grab the gc lock twice.
Jul 17 2014