January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #20 from Don <clugdbug@yahoo.com.au> 2013-01-10 01:14:30 PST ---
(In reply to comment #18)
> (In reply to comment #17)
> > Windows inserts a "guard page" that is hardware protected beyond the end of the allocated stack. A stack overflow runs into that guard page, which throws a seg fault.
> > 
> > It does not corrupt memory.
> 
> What about the rest of the platforms?

On our code (Linux only, derived from Tango, its basically the same as druntime) our fibers allocate a guard page at the end of the stack. We added this because we found that stack overflows in fibers are easy to create but difficult to debug.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #21 from bearophile_hugs@eml.cc 2013-01-10 01:46:38 PST ---
(In reply to comment #17)
> Windows inserts a "guard page" that is hardware protected beyond the end of the allocated stack. A stack overflow runs into that guard page, which throws a seg fault.
> 
> It does not corrupt memory.

So what's missing is just the stack trace.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #22 from Andrei Alexandrescu <andrei@erdani.com> 2013-01-10 09:08:49 PST ---
How large are the guard pages on each OS?

We should either restrict object size to a reasonable maximum, or insert runtime checks at least in @safe mode when accessing fields through pointers that may be null.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #23 from Andrei Alexandrescu <andrei@erdani.com> 2013-01-10 09:12:28 PST ---
Oh there's also a confusion. The problem is not with the stack, it's with accessing fields through null pointers. Getting back to the original example:

struct S {
    char raw[100_000];
}

void main() {
  S * s = null;
  char a = raw[$ - 1];
}

That will issue an access through a pointer with a small value (100_000). The question is what is the maximum small pointer that will cause a protection fault on all OSs.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #24 from Jacob Carlborg <doob@me.com> 2013-01-10 10:14:47 PST ---
(In reply to comment #22)
> How large are the guard pages on each OS?
> 
> We should either restrict object size to a reasonable maximum, or insert runtime checks at least in @safe mode when accessing fields through pointers that may be null.

Perhaps doing something similar as with array bounds checking. Insert a check and provide a compiler flag to remove it. Or remove the check in -release builds.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #25 from hsteoh@quickfur.ath.cx 2013-01-10 11:46:07 PST ---
(In reply to comment #17)
> Windows inserts a "guard page" that is hardware protected beyond the end of the allocated stack. A stack overflow runs into that guard page, which throws a seg fault.
> 
> It does not corrupt memory.

Oh yes it does:

http://d.puremagic.com/test-results/pull.ghtml?projectid=1&runid=448588

(But I did make a mistake, it's not Linux that this happens on, but OSX/64.)

For reference, this is the failing code (N.B. the last assert, compare with output in the autotester, you can see that garbage values are produced, I've traced this and found that it's caused by stack overflow):

unittest
{
    struct TransientRange
    {
        dchar[128] _buf;
        dstring[] _values;
        this(dstring[] values)
        {
            _values = values;
        }
        @property bool empty()
        {
            return _values.length == 0;
        }
        @property auto front()
        {
            foreach (i; 0 .. _values.front.length)
            {
                _buf[i] = _values[0][i];
            }
            return _buf[0 .. _values.front.length];
        }
        void popFront()
        {
            _values = _values[1 .. $];
        }
    }

    auto rr = TransientRange(["abc"d, "12"d, "def"d, "34"d]);

    // Can't use array() or equal() directly because they fail with transient
    // .front.
    dchar[] result;
    foreach (c; rr.joiner()) {
        result ~= c;
    }

    assert(equal(result, "abc12def34"d),
        "Unexpected result: '%s'"d.format(result));
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #26 from Walter Bright <bugzilla@digitalmars.com> 2013-01-10 12:03:50 PST ---
(In reply to comment #22)
> How large are the guard pages on each OS?

Usually 4k. But the function prologs, when creating a stack frame larger than 4k, will do "probes" for each 4k page. So, no, you can't corrupt memory with an overflow.

> We should either restrict object size to a reasonable maximum, or insert runtime checks at least in @safe mode when accessing fields through pointers that may be null.

There's a separate set of guard pages at address 0, to cause a seg fault if 1, 2, 3, etc. is accessed. I don't know how big they are.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
January 10, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #27 from Walter Bright <bugzilla@digitalmars.com> 2013-01-10 12:08:12 PST ---
> Oh yes it does:

You can test this with a far simpler program. Just write a function that calls itself and run it under the debugger.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 20, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176


9999 <sibaqexozequgaba@tempomail.fr> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |sibaqexozequgaba@tempomail.
                   |                            |fr


--- Comment #28 from 9999 <sibaqexozequgaba@tempomail.fr> 2013-05-20 00:58:57 PDT ---
Copying my comment from the forums so it won't get lost: (http://forum.dlang.org/post/fuqkpmkfdjxwgmzfizuu@forum.dlang.org)

Isn't the solution as easy as doing:
OR PTR:[address], 0
the same way it's done for the stack?

The offset it known at compile time in most cases, so the command
would be required only if both:
* The object is larger than target OS' guard page size.
* The position is greater than target OS' guard page size, OR is
unknown at compile time.

Walter: "Not a bad idea." :)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
May 20, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=5176



--- Comment #29 from deadalnix <deadalnix@gmail.com> 2013-05-20 01:07:53 PDT ---
(In reply to comment #28)
> Copying my comment from the forums so it won't get lost: (http://forum.dlang.org/post/fuqkpmkfdjxwgmzfizuu@forum.dlang.org)
> 
> Isn't the solution as easy as doing:
> OR PTR:[address], 0
> the same way it's done for the stack?
> 
> The offset it known at compile time in most cases, so the command
> would be required only if both:
> * The object is larger than target OS' guard page size.
> * The position is greater than target OS' guard page size, OR is
> unknown at compile time.
> 
> Walter: "Not a bad idea." :)

The thing is that you may get over the page protection by several dereferences. So you must check based not on the dereferenced address, but on the maximum addres that will be dereferenced (ie the end of the object).

It means that every single reference taking on a 4kb+ object must have a check.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------