structs holding on to reference data by pointer

Maxim Fomin maxim at maxim-fomin.ru
Thu Oct 31 10:49:51 PDT 2013


On Thursday, 31 October 2013 at 17:34:21 UTC, Daniel Davidson 
wrote:
> On Thursday, 31 October 2013 at 16:16:36 UTC, bearophile wrote:
>>
>> That's wrong code, you are escaping a reference to memory (of 
>> rc variable) allocated in the stack frame of foo(). The D 
>> compiler is not smart enough to recognize the bug. There are 
>> optimizations that patch and avoid this bug (like inlining, or 
>> allocating rc inside the stack frame of the main) but you 
>> can't rely on them.
>>
>
> Ahh ok. Because of issues with const members (copying them when 
> they are composed in other classes does not work well) I'm 
> trying to get around the copy by storing reference data as 
> const(T) *. This is why I'm asking. So here are some follow ups:
>
> - As I see it there is grave risk. Is the risk introduced by 
> the fact that I am storing a member as const(T)*?

Risk is that pointer to local variable is escaped, not because it 
is stored in const qualified pbject.

> - I assume that if I had created the RC instance on the heap 
> there would be no problems. Is there a way in general to ensure 
> that a const(T)* is referring to something on the heap as 
> opposed to the stack (ideally at compile time).

Yes, you can explicitly allocate on heap. You can check whether 
data is on heap, stack, tls, or just global object by inspecting 
pointer at runtime. Ideally there would be such function in 
druntime. It is impossible to do this in CT (except if comiler 
support flow analysis and can prove in some scenarious that data 
is on stack or not, but due to separate compilation it is 
impossible to do in general case) (and probably shouldn't).

> - What is the root problem - having a const(T)* member which 
> then requires code to take address, or taking address? My first 
> thought was, just never take address of local static variable - 
> which is generally good advice. But once you are in a function 
> that takes ref const(T) you can take the address of that as 
> well - see modification below. This suffers the same problem 
> but in a less obvious way.
>
> Any suggestions welcome.
>
> Thanks
> Dan
>
> import opmix.mix;
> import plus.tvm.rate_curve;
> import std.stdio;
>
> struct RC {
>   this(this) { data = data.dup; }
>   int[] data;
> }
>
> struct T {
>   const(RC) *rc;
>   void goo() {
>     writeln("Data is ", rc.data);
>   }
> }
>
> T goo(ref RC rc) {
>   return T(&rc);
> }
>
> T foo() {
>   RC rc = { [1,2,3] };
>   writeln("Address is ", &rc);
>   return goo(rc);
> }
>
> void main() {
>   T t = foo();
>   t.goo();
>   writeln("Address is ", t.rc);
> }

Yes, this is known issue. There are lots of other tricks to break 
the language.


More information about the Digitalmars-d-learn mailing list