www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Antipattern in core.memory.GC.addRange?

reply Steven Schveighoffer <schveiguy yahoo.com> writes:
GC.addRange has this signature:

static nothrow  nogc void addRange(in void* p, size_t sz, const TypeInfo 
ti = null);

I see a large problem with this. Let's say you malloc an array of struct 
pointers:

struct Foo { ... }

import core.stdc.stdlib;
auto ptrs = (cast(Foo *)malloc(Foo.sizeof * 10))[0 .. 10];

Now, you want to store GC pointers in that block, you need to add the 
range to the GC:

GC.addRange(ptrs.ptr, ptrs.length);

See the problem? Why would addRange work this way, when D has such a 
better mechanism for this? Can we fix it?

-Steve
Sep 22 2017
next sibling parent reply safety0ff <safety0ff.dev gmail.com> writes:
On Friday, 22 September 2017 at 21:29:10 UTC, Steven 
Schveighoffer wrote:
 GC.addRange has this signature:

 static nothrow  nogc void addRange(in void* p, size_t sz, const 
 TypeInfo ti = null);

 I see a large problem with this. Let's say you malloc an array 
 of struct pointers:

 struct Foo { ... }

 import core.stdc.stdlib;
 auto ptrs = (cast(Foo *)malloc(Foo.sizeof * 10))[0 .. 10];

 Now, you want to store GC pointers in that block, you need to 
 add the range to the GC:

 GC.addRange(ptrs.ptr, ptrs.length);

 See the problem?
Yes, you forgot to multiply by Foo.sizeof. Using the pattern from the example in the documentation, the code would be: size_t bytes = Foo.sizeof * 10; auto ptrs = (cast(Foo *)malloc(bytes))[0 .. 10]; GC.addRange(ptrs.ptr, bytes);
Sep 22 2017
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/23/17 1:30 AM, safety0ff wrote:
 On Friday, 22 September 2017 at 21:29:10 UTC, Steven Schveighoffer wrote:
 GC.addRange has this signature:

 static nothrow  nogc void addRange(in void* p, size_t sz, const 
 TypeInfo ti = null);

 I see a large problem with this. Let's say you malloc an array of 
 struct pointers:

 struct Foo { ... }

 import core.stdc.stdlib;
 auto ptrs = (cast(Foo *)malloc(Foo.sizeof * 10))[0 .. 10];

 Now, you want to store GC pointers in that block, you need to add the 
 range to the GC:

 GC.addRange(ptrs.ptr, ptrs.length);

 See the problem?
Yes, you forgot to multiply by Foo.sizeof. Using the pattern from the example in the documentation, the code would be: size_t bytes = Foo.sizeof * 10; auto ptrs = (cast(Foo *)malloc(bytes))[0 .. 10]; GC.addRange(ptrs.ptr, bytes);
Right, the problem is that the API accepts this without error, because of the implicit cast to void *. The simple rule should be that if we can prevent something obviously wrong from compiling, we should do so. -Steve
Sep 23 2017
prev sibling parent reply Petar Kirov [ZombineDev] <petar.p.kirov gmail.com> writes:
On Friday, 22 September 2017 at 21:29:10 UTC, Steven 
Schveighoffer wrote:
 GC.addRange has this signature:

 static nothrow  nogc void addRange(in void* p, size_t sz, const 
 TypeInfo ti = null);

 I see a large problem with this. Let's say you malloc an array 
 of struct pointers:

 struct Foo { ... }

 import core.stdc.stdlib;
 auto ptrs = (cast(Foo *)malloc(Foo.sizeof * 10))[0 .. 10];

 Now, you want to store GC pointers in that block, you need to 
 add the range to the GC:

 GC.addRange(ptrs.ptr, ptrs.length);

 See the problem? Why would addRange work this way, when D has 
 such a better mechanism for this? Can we fix it?

 -Steve
How about adding a template wrapper function, along the lines of: static void addRange(T)(const T[] arr) { addRange(arr.ptr, T.sizeof * arr.length, typeid(T)); } To core.memory.GC?
Sep 22 2017
parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/23/17 1:55 AM, Petar Kirov [ZombineDev] wrote:

 
 How about adding a template wrapper function, along the lines of:
 static void addRange(T)(const T[] arr)
 {
      addRange(arr.ptr, T.sizeof * arr.length, typeid(T));
 }
 
 
 To core.memory.GC?
It sounds good. But will it be accepted? Note, the true implementation should use integer overflow to reject invalid arrays. -Steve
Sep 23 2017