www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - testing if data is allocated on the stack or heap

reply drug <drug2004 bk.ru> writes:
My code fails and I guess the reason is I have a slice to data in the 
stack and it becomes garbage in some moment. So I need a way to check 
where data is placed. Is it right that it can be done in linux using 
`sbrk` so that if the addr of data is less than `sbrk(0)` returning then 
data is on the stack and on the heap in other case?
Oct 17 2017
next sibling parent drug <drug2004 bk.ru> writes:
https://run.dlang.io/is/vOh6YY
Oct 17 2017
prev sibling next sibling parent reply Biotronic <simen.kjaras gmail.com> writes:
On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 My code fails and I guess the reason is I have a slice to data 
 in the stack and it becomes garbage in some moment. So I need a 
 way to check where data is placed. Is it right that it can be 
 done in linux using `sbrk` so that if the addr of data is less 
 than `sbrk(0)` returning then data is on the stack and on the 
 heap in other case?
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. module stackCheck; private size_t stackStart; enum size_t pageSize = 0x1000; static this() { import core.stdc.stdlib : alloca; stackStart = cast(size_t)alloca(size_t.sizeof) & ~(pageSize-1); } bool onStack(void* p) { size_t end = (cast(size_t)&p & ~(pageSize-1)) + pageSize; size_t pp = cast(size_t)p; if (end > stackStart) { return pp >= stackStart && pp <= end; } else { return pp <= stackStart && pp >= end; } } bool onStack(T)(ref T p) { return (&p).onStack; } unittest { int n; int* p = new int; assert(n.onStack); assert(!p.onStack); } -- Biotronic
Oct 17 2017
next sibling parent drug <drug2004 bk.ru> writes:
17.10.2017 20:27, Biotronic пишет:
 module stackCheck;
 
 private size_t stackStart;
 enum size_t pageSize = 0x1000;
 
 static this() {
      import core.stdc.stdlib : alloca;
      stackStart = cast(size_t)alloca(size_t.sizeof) & ~(pageSize-1);
 }
 
 bool onStack(void* p) {
      size_t end = (cast(size_t)&p & ~(pageSize-1)) + pageSize;
      size_t pp = cast(size_t)p;
 
      if (end > stackStart) {
          return pp >= stackStart && pp <= end;
      } else {
          return pp <= stackStart && pp >= end;
      }
 }
 
 bool onStack(T)(ref T p) {
      return (&p).onStack;
 }
 
 unittest {
      int n;
      int* p = new int;
 
      assert(n.onStack);
      assert(!p.onStack);
 }
Thanks! Your solution not only works but is portable also.
Oct 17 2017
prev sibling next sibling parent user1234 <user1234 12.nl> writes:
On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:
 On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 [...]
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. [...]
Nice solution. Is `stackStart` thread local on purpose?
Oct 17 2017
prev sibling parent reply flamencofantasy <flamencofantasy gmail.com> writes:
On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:
 On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 [...]
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. [...]
Try this; unittest { int[5*1024] n; int* p = new int; assert(n.onStack); assert(!p.onStack); }
Oct 17 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 10/17/17 7:32 PM, flamencofantasy wrote:
 On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:
 On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 [...]
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. [...]
Try this; unittest {     int[5*1024] n;     int* p = new int;     assert(n.onStack);     assert(!p.onStack); }
The second is wrong. You are asserting that the storage of p is not on the stack, but it is. What p *points at* is not on the stack. So the correct call should be: assert(!(*p).onStack); or (IMO) less ugly: assert(!onStack(*p)); -Steve
Oct 17 2017
next sibling parent flamencofantasy <flamencofantasy gmail.com> writes:
On Tuesday, 17 October 2017 at 23:59:19 UTC, Steven Schveighoffer 
wrote:
 On 10/17/17 7:32 PM, flamencofantasy wrote:
 On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:
 On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 [...]
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. [...]
Try this; unittest {     int[5*1024] n;     int* p = new int;     assert(n.onStack);     assert(!p.onStack); }
The second is wrong. You are asserting that the storage of p is not on the stack, but it is. What p *points at* is not on the stack. So the correct call should be: assert(!(*p).onStack); or (IMO) less ugly: assert(!onStack(*p)); -Steve
you misunderstood, the code is from biotronic's post, i just made a static array of 5kb to point out how it fails, in just one way out of a dozen other possibilities.
Oct 17 2017
prev sibling parent reply Biotronic <simen.kjaras gmail.com> writes:
On Tuesday, 17 October 2017 at 23:59:19 UTC, Steven Schveighoffer 
wrote:
 On 10/17/17 7:32 PM, flamencofantasy wrote:
 On Tuesday, 17 October 2017 at 17:27:17 UTC, Biotronic wrote:
 On Tuesday, 17 October 2017 at 15:33:02 UTC, drug wrote:
 [...]
I have very little knowledge about sbrk, so here's my solution. Tested on win32 and win64. [...]
Try this; unittest {     int[5*1024] n;     int* p = new int;     assert(n.onStack);     assert(!p.onStack); }
The second is wrong. You are asserting that the storage of p is not on the stack, but it is. What p *points at* is not on the stack. So the correct call should be: assert(!(*p).onStack); or (IMO) less ugly: assert(!onStack(*p)); -Steve
No, the second is correct - the ref overload is only chosen when p is not implicitly castable to void*. In fact, the second assert passes, it's the first one that causes problems. I've written an improved version, that probably still has problems. If flamencofantasy would like to point out other shortcomings, I'd love to learn. module stackCheck; private size_t stackStart; enum size_t pageSize = 0x1000; static this() { import core.stdc.stdlib : alloca; stackStart = cast(size_t)alloca(size_t.sizeof); } bool onStack(void* p) { size_t end = cast(size_t)&p; size_t pp = cast(size_t)p; size_t ss = stackStart; if (end > ss) { end &= ~(pageSize-1); ss &= ~(pageSize-1); end += pageSize; return pp >= ss && pp <= end; } else { end &= ~(pageSize-1); ss &= ~(pageSize-1); ss += pageSize; return pp <= ss && pp >= end; } } bool onStack(T)(ref T p) { return (&p).onStack; } unittest { int n; int* p = new int; assert(n.onStack); assert(!p.onStack); } unittest { int[5*1023] n; int* p = new int; assert(n.onStack); assert(!p.onStack); }
Oct 18 2017
parent Biotronic <simen.kjaras gmail.com> writes:
It's worth pointing out, btw, that the main reason for this code 
is to help drug diagnose his or her problem, not to be the 
be-all, end-all of stack identifying functions. :)

It will of course not correctly identify pointers to variables on 
other threads' stacks, and fiber stacks probably trip it up bad.

--
   Biotronic
Oct 18 2017
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, October 17, 2017 18:33:02 drug via Digitalmars-d-learn wrote:
 My code fails and I guess the reason is I have a slice to data in the
 stack and it becomes garbage in some moment. So I need a way to check
 where data is placed. Is it right that it can be done in linux using
 `sbrk` so that if the addr of data is less than `sbrk(0)` returning then
 data is on the stack and on the heap in other case?
In theory, safe is supposed to help with this such that any code that sliced a static array would be system or trusted, which would seriously narrow down the search space when something goes wrong with memory, but the slicing of static arrays typically being treated as safe is one of the major, outstanding bugs for safe. It looks like it's now caught when simply returning a slice of a static array, but simply slicing a static array is still considered safe (even though taking the address of a local variable does, and it's really the same thing). So, if you try and use safe throughout your code, you'll find _some_ of the potential memory problems but not all of them. All of the work that Walter has been doing with DIP 1000 should help though. - Jonathan M Davis
Oct 18 2017