www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Leak-detection of references to scoped class instances

reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
Why doesn't DMD detect invalid out-of-scope references to scoped 
class instances?

Example:

 safe:

class C
{
 safe pure:
     this()
     {
     }
     int x;
}

 trusted unittest
{
     C f()
     {
         import std.typecons : scoped;
         auto x = scoped!C();
         return x;
     }
     auto c = f();
     c.x = 42;                   // invalid memory access
}
Nov 24 2019
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
"Allocates a class object right inside the current scope, therefore 
avoiding the overhead of new. This facility is unsafe; it is the 
responsibility of the user to not escape a reference to the object 
outside the scope."

https://dlang.org/phobos/std_typecons.html#.scoped
Nov 24 2019
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 24 November 2019 at 12:51:53 UTC, rikki cattermole 
wrote:
 "Allocates a class object right inside the current scope, 
 therefore avoiding the overhead of new. This facility is 
 unsafe; it is the responsibility of the user to not escape a 
 reference to the object outside the scope."

 https://dlang.org/phobos/std_typecons.html#.scoped
Why doesn't DIP-1000 include such escape analysis?
Nov 24 2019
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 24 November 2019 at 14:19:23 UTC, Per Nordlöw wrote:
 Why doesn't DIP-1000 include such escape analysis?
did you enable it with the command line switch? furthermore i *think* it onyl works o safe stuff, not trusted stuff.
Nov 24 2019
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 24 November 2019 at 14:21:48 UTC, Adam D. Ruppe wrote:
 On Sunday, 24 November 2019 at 14:19:23 UTC, Per Nordlöw wrote:
 Why doesn't DIP-1000 include such escape analysis?
did you enable it with the command line switch? furthermore i *think* it onyl works o safe stuff, not trusted stuff.
Yes, I did. As you remind me of DIP-1000 is only activate in safe code. I guess we need a builtin language qualifier for scoped classes for that to work, right?
Nov 24 2019
parent reply Jacob Carlborg <doob me.com> writes:
On Sunday, 24 November 2019 at 21:49:19 UTC, Per Nordlöw wrote:
 I guess we need a builtin language qualifier for scoped classes 
 for that to work, right?
We have that: scope a = new Object; — /Jacob Carlborg
Nov 25 2019
parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 25 November 2019 at 08:22:02 UTC, Jacob Carlborg wrote:
 On Sunday, 24 November 2019 at 21:49:19 UTC, Per Nordlöw wrote:
 I guess we need a builtin language qualifier for scoped 
 classes for that to work, right?
We have that: scope a = new Object; — /Jacob Carlborg
Ahh, nice. Does/Will DMD/GDC/LDC (in release builds) make the allocation of `Object` happen on the stack?
Nov 25 2019
parent reply mipri <mipri minimaltype.com> writes:
On Monday, 25 November 2019 at 12:08:54 UTC, Per Nordlöw wrote:
 On Monday, 25 November 2019 at 08:22:02 UTC, Jacob Carlborg 
 wrote:
 On Sunday, 24 November 2019 at 21:49:19 UTC, Per Nordlöw wrote:
 I guess we need a builtin language qualifier for scoped 
 classes for that to work, right?
We have that: scope a = new Object; — /Jacob Carlborg
Ahh, nice. Does/Will DMD/GDC/LDC (in release builds) make the allocation of `Object` happen on the stack?
class C { int x; this(int n) { x = n; } } int heap() { auto x = new C(2); // vgc: `new` causes a GC allocation return x.x; } /+ int example.heap(): sub rsp, 8 mov edi, OFFSET FLAT:example.C.__Class call _d_newclass mov DWORD PTR [rax+16], 2 mov eax, 2 add rsp, 8 ret +/ int stack() { scope x = new C(2); // (no vgc output) return x.x; } /+ int example.stack(): sub rsp, 40 mov rdi, rsp mov QWORD PTR [rsp], OFFSET FLAT:example.C.__vtbl mov QWORD PTR [rsp+8], 0 mov DWORD PTR [rsp+16], 2 call _d_callfinalizer mov eax, 2 add rsp, 40 ret +/ gdc assembly. ldc eliminates the object entirely.
Nov 25 2019
next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 25 November 2019 at 13:09:44 UTC, mipri wrote:
 gdc assembly. ldc eliminates the object entirely.
Thanks.
Nov 25 2019
prev sibling next sibling parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 25 November 2019 at 13:09:44 UTC, mipri wrote:
 gdc assembly. ldc eliminates the object entirely.
DIP-1000 kicks comes to the rescue here aswell: class C { safe pure nothrow nogc: this(int x) { this.x = x; } int x; } C leakClass() safe pure nothrow { scope x = new C(42); return x; // Error: scope variable `x` may not be returned } safe pure nothrow unittest { auto x = leakClass(); } Brilliant!
Nov 25 2019
prev sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Monday, 25 November 2019 at 13:09:44 UTC, mipri wrote:
 class C {
     int x;
     this(int n) { x = n; }
 }

 int heap() {
     auto x = new C(2); // vgc: `new` causes a GC allocation
     return x.x;
 }
 /+
 int example.heap():
         sub     rsp, 8
         mov     edi, OFFSET FLAT:example.C.__Class
         call    _d_newclass
         mov     DWORD PTR [rax+16], 2
         mov     eax, 2
         add     rsp, 8
         ret
 +/
 gdc assembly.
What about adding a new optimization pass to the compiler that infers `scope` of each class instance `x` if it (and all it's aliasings) are - only passed to scope parameters of functions and - doesn't escape into a global variable or via a return value ? I recall such as mechanism already exists for GC-allocated dynamic arrays which, in release builds of ldc at least, are replaced with stack-allocated arrays (if they are small enough). Also, what happens if `C` doesn't fit on the stack? In that case the compiler should allocate `C` using a deterministic allocator via `malloc` or `mmap` and `free` or `munmap` the instance at the end of `x`'s lifetime.
Nov 28 2019
parent IGotD- <nise nise.com> writes:
On Thursday, 28 November 2019 at 21:49:09 UTC, Per
 Also, what happens if `C` doesn't fit on the stack?
This is OS specific I think. For example on Linux at the end of the stack there is a guard page and when you hit it the process will segfault.
Nov 29 2019