Thread overview
question about keeeping reference to toStringz()
May 30, 2018
Dr.No
May 30, 2018
Ali Çehreli
May 31, 2018
Dr.No
May 31, 2018
Jonathan M Davis
May 31, 2018
Mike Parker
May 31, 2018
bauss
May 30, 2018
The documentation says:

Important Note: When passing a char* to a C function, and the C function keeps it around for any reason, make sure that you keep a reference to it in your D code. Otherwise, it may become invalid during a garbage collection cycle and cause a nasty bug when the C code tries to use it.

(from https://dlang.org/library/std/string/to_stringz.html)

consider a C function with this prototype:
>void foo(const char *baa);

Does it means I should do:

> string s = ...;
> auto cstring = s.toStringz;
> foo(cstring);

rather just:

> foo(s.toStringz);

?
May 30, 2018
On 05/30/2018 01:09 PM, Dr.No wrote:

> consider a C function with this prototype:
>> void foo(const char *baa);
>
> Does it means I should do:
>
>> string s = ...;
>> auto cstring = s.toStringz;
>> foo(cstring);
>
> rather just:
>
>> foo(s.toStringz);
>
> ?

It depends. cstring method above is not sufficient if cstring's life is shorter than the C library's use:

void bar() {
    string s = ...;
    auto cstring = s.toStringz;
    foo(cstring);

} // <- cstring is gone

What if the library saved that pointer while performing foo()?

If cstring is in module-scope or in a container (e.g. an array) that's in module-scope then it's fine. But then, you would have to remove it from that container when the C library does not need that pointer anymore.

Ali

May 31, 2018
On Wednesday, 30 May 2018 at 20:43:48 UTC, Ali Çehreli wrote:
> On 05/30/2018 01:09 PM, Dr.No wrote:
>
> > consider a C function with this prototype:
> >> void foo(const char *baa);
> >
> > Does it means I should do:
> >
> >> string s = ...;
> >> auto cstring = s.toStringz;
> >> foo(cstring);
> >
> > rather just:
> >
> >> foo(s.toStringz);
> >
> > ?
>
> It depends. cstring method above is not sufficient if cstring's life is shorter than the C library's use:
>
> void bar() {
>     string s = ...;
>     auto cstring = s.toStringz;
>     foo(cstring);
>
> } // <- cstring is gone
>
> What if the library saved that pointer while performing foo()?
>
> If cstring is in module-scope or in a container (e.g. an array) that's in module-scope then it's fine. But then, you would have to remove it from that container when the C library does not need that pointer anymore.
>
> Ali

is foo() is being called from a thread, how I am supposed to keep cstring "alive"?
May 30, 2018
On Thursday, May 31, 2018 01:12:34 Dr.No via Digitalmars-d-learn wrote:
> On Wednesday, 30 May 2018 at 20:43:48 UTC, Ali Çehreli wrote:
> > On 05/30/2018 01:09 PM, Dr.No wrote:
> > > consider a C function with this prototype:
> > >> void foo(const char *baa);
> > >
> > > Does it means I should do:
> > >> string s = ...;
> > >> auto cstring = s.toStringz;
> > >> foo(cstring);
> > >
> > > rather just:
> > >> foo(s.toStringz);
> > >
> > > ?
> >
> > It depends. cstring method above is not sufficient if cstring's life is shorter than the C library's use:
> >
> > void bar() {
> >
> >     string s = ...;
> >     auto cstring = s.toStringz;
> >     foo(cstring);
> >
> > } // <- cstring is gone
> >
> > What if the library saved that pointer while performing foo()?
> >
> > If cstring is in module-scope or in a container (e.g. an array) that's in module-scope then it's fine. But then, you would have to remove it from that container when the C library does not need that pointer anymore.
> >
> > Ali
>
> is foo() is being called from a thread, how I am supposed to keep
> cstring "alive"?

If it's being passed to foo, then it should be on the stack until foo returns, in which case, the GC should see it when it scans. It's when foo could keep a reference to the pointer that you have a problem, since then as soon as foo returns, the pointer you passed to foo won't be on the stack anymore. So, in that case, you'd have to store the pointer somewhere in D code so that the GC will see it when scanning.

Or are you concerned about something like spinning up a thread, calling foo, and then exiting the thread while foo stores the pointer somewhere? If that's the case, then you'll need to store the pointer in a shared or __gshared variable in D code so that you can still refer to it after the thread terminates.

- Jonathan M Davis


May 31, 2018
On Thursday, 31 May 2018 at 01:12:34 UTC, Dr.No wrote:

>
> is foo() is being called from a thread, how I am supposed to keep cstring "alive"?

As Jonathan explained, you don't have to worry about it if foo() itself doesn't assign the pointer to anything internally. That will be the case for most C functions. Well-behaved functions that need to keep the string around will copy it. That said, you need to be sure you understand fully what any C function you call is doing with the strings, or pointers to any memory allocated by the GC, that you pass to them.

In the rare cases where the C function does keep the pointer and you do need to keep a reference (if you don't have one already), the simplest approach is this one:

import core.memory;
GC.addRoot(cstring);

Then, when you no longer need it:
GC.removeRoot(cstring);

https://dlang.org/phobos/core_memory.html#.GC.addRoot



May 31, 2018
On Thursday, 31 May 2018 at 02:10:53 UTC, Mike Parker wrote:
> On Thursday, 31 May 2018 at 01:12:34 UTC, Dr.No wrote:
>
>>
>> is foo() is being called from a thread, how I am supposed to keep cstring "alive"?
>
> As Jonathan explained, you don't have to worry about it if foo() itself doesn't assign the pointer to anything internally. That will be the case for most C functions. Well-behaved functions that need to keep the string around will copy it. That said, you need to be sure you understand fully what any C function you call is doing with the strings, or pointers to any memory allocated by the GC, that you pass to them.
>
> In the rare cases where the C function does keep the pointer and you do need to keep a reference (if you don't have one already), the simplest approach is this one:
>
> import core.memory;
> GC.addRoot(cstring);
>
> Then, when you no longer need it:
> GC.removeRoot(cstring);
>
> https://dlang.org/phobos/core_memory.html#.GC.addRoot

Actually thank you for this.

I had no idea you could do that with the GC.