July 13, 2014
On Sunday, 13 July 2014 at 03:25:08 UTC, Walter Bright wrote:
> On 7/11/2014 10:28 AM, deadalnix wrote:
>> The compiler can ensure that you hit at least every 4k or so.
>
> And it already does.

Doesn't look so:

    int foo(int a) {
        int[100] b = void;
        b[$-1] = a;
        return b[$-1];
    }

    int bar(int a) {
        int[8000] b = void;
        b[$-1] = a;
        return b[$-1];
    }

# objdump -d bigstack.o | ddemangle | less

Disassembly of section .text.int bigstack.foo(int):

0000000000000000 <int bigstack.foo(int)>:
   0:   55                      push   %rbp
   1:   48 8b ec                mov    %rsp,%rbp
   4:   48 81 ec a0 01 00 00    sub    $0x1a0,%rsp
   b:   48 8d 45 f4             lea    -0xc(%rbp),%rax
   f:   89 38                   mov    %edi,(%rax)
  11:   8b 45 f4                mov    -0xc(%rbp),%eax
  14:   c9                      leaveq
  15:   c3                      retq
  16:   66 90                   xchg   %ax,%ax

Disassembly of section .text.int bigstack.bar(int):

0000000000000000 <int bigstack.bar(int)>:
   0:   55                      push   %rbp
   1:   48 8b ec                mov    %rsp,%rbp
   4:   48 81 ec 10 7d 00 00    sub    $0x7d10,%rsp
   b:   48 8d 45 f4             lea    -0xc(%rbp),%rax
   f:   89 38                   mov    %edi,(%rax)
  11:   8b 45 f4                mov    -0xc(%rbp),%eax
  14:   c9                      leaveq
  15:   c3                      retq
  16:   66 90                   xchg   %ax,%ax

(This is with DMD master on Linux x86_64. Same with -m32.)
July 13, 2014
On 7/13/2014 4:04 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
> On Sunday, 13 July 2014 at 03:25:08 UTC, Walter Bright wrote:
>> On 7/11/2014 10:28 AM, deadalnix wrote:
>>> The compiler can ensure that you hit at least every 4k or so.
>>
>> And it already does.
>
> Doesn't look so:
>

>      int bar(int a) {
>          int[8000] b = void;
>          b[$-1] = a;
>          return b[$-1];
>      }

On Win32:

_D4foo53barFiZi comdat
        assume  CS:_D4foo53barFiZi
                push    EBP
                mov     EBP,ESP
                mov     EDX,7
L8:             sub     ESP,01000h
                test    [ESP],ESP
                dec     EDX
                jne     L8
                sub     ESP,0D04h
                lea     ECX,-8[EBP]
                mov     [ECX],EAX
                mov     EAX,-8[EBP]
                leave
                ret

It doesn't do it on Linux because gcc doesn't do it. But the capability is in the back end, and it does it for alloca(), too.
July 14, 2014
On Sunday, 13 July 2014 at 23:35:46 UTC, Walter Bright wrote:
> On 7/13/2014 4:04 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
>> On Sunday, 13 July 2014 at 03:25:08 UTC, Walter Bright wrote:
>>> On 7/11/2014 10:28 AM, deadalnix wrote:
>>>> The compiler can ensure that you hit at least every 4k or so.
>>>
>>> And it already does.
>>
>> Doesn't look so:
>>
>
>>     int bar(int a) {
>>         int[8000] b = void;
>>         b[$-1] = a;
>>         return b[$-1];
>>     }
>
> On Win32:
>
> _D4foo53barFiZi comdat
>         assume  CS:_D4foo53barFiZi
>                 push    EBP
>                 mov     EBP,ESP
>                 mov     EDX,7
> L8:             sub     ESP,01000h
>                 test    [ESP],ESP
>                 dec     EDX
>                 jne     L8
>                 sub     ESP,0D04h
>                 lea     ECX,-8[EBP]
>                 mov     [ECX],EAX
>                 mov     EAX,-8[EBP]
>                 leave
>                 ret
>
> It doesn't do it on Linux because gcc doesn't do it. But the capability is in the back end, and it does it for alloca(), too.

Hmm... but this using DMD, not GDC. Or do you mean that DMD doesn't do it, because GCC doesn't do it either? If so, what is the reason for this? Why shouldn't this feature be enabled on every platform?
July 14, 2014
On 7/14/2014 3:07 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
> Hmm... but this using DMD, not GDC. Or do you mean that DMD doesn't do it,
> because GCC doesn't do it either?

Right.


> If so, what is the reason for this? Why
> shouldn't this feature be enabled on every platform?

There are often undocumented reasons why gcc generates code in certain ways, and I figured that being compatible was the best strategy. Every time I deviate, it comes back eventually as a bug report.
July 14, 2014
On 14 July 2014 11:07, via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On Sunday, 13 July 2014 at 23:35:46 UTC, Walter Bright wrote:
>>
>> On 7/13/2014 4:04 AM, "Marc Schütz" <schuetzm@gmx.net>" wrote:
>>>
>>> On Sunday, 13 July 2014 at 03:25:08 UTC, Walter Bright wrote:
>>>>
>>>> On 7/11/2014 10:28 AM, deadalnix wrote:
>>>>>
>>>>> The compiler can ensure that you hit at least every 4k or so.
>>>>
>>>>
>>>> And it already does.
>>>
>>>
>>> Doesn't look so:
>>>
>>
>>>     int bar(int a) {
>>>         int[8000] b = void;
>>>         b[$-1] = a;
>>>         return b[$-1];
>>>     }
>>
>>
>> On Win32:
>>
>> _D4foo53barFiZi comdat
>>         assume  CS:_D4foo53barFiZi
>>                 push    EBP
>>                 mov     EBP,ESP
>>                 mov     EDX,7
>> L8:             sub     ESP,01000h
>>                 test    [ESP],ESP
>>                 dec     EDX
>>                 jne     L8
>>                 sub     ESP,0D04h
>>                 lea     ECX,-8[EBP]
>>                 mov     [ECX],EAX
>>                 mov     EAX,-8[EBP]
>>                 leave
>>                 ret
>>
>> It doesn't do it on Linux because gcc doesn't do it. But the capability is in the back end, and it does it for alloca(), too.
>
>
> Hmm... but this using DMD, not GDC. Or do you mean that DMD doesn't do it, because GCC doesn't do it either? If so, what is the reason for this? Why shouldn't this feature be enabled on every platform?


For GDC, there is -fstack-protector (which is turned on by default in distributed binaries from Ubuntu).  However IIRC only functions that use alloca or have static arrays of type char are actually checked. Declaring an int[100] doesn't invoke alloca, so you won't see it.

The bounds checking in D alone is enough to catch most common overflowing stack bugs.

Regards
Iain

July 20, 2014
Returning to the earlier question, of helping to avoid stack
overflows:
I can easily think of two things the language could do.
(Forgive me if D already has them - I have read a fair amount but
not all the minutiae.)

1) A function annotation that means "I will call myself
recursively, and when I do, I expect the tail recursion
optimization." I have seen code which allocates something big on
the stack and depends on the optimization. So this intent should
be expressible.

2) Annotations about when a function does not expect re-entrancy
to be possible based on call-graph analysis. This would obviously
have to restrict what it can do in order to be feasible, but
wouldn't it still be useful? Besides - the cases where it is hard
for the compiler to detect the possibility of re-entrancy are
often cases where humans have trouble noticing it too.
July 20, 2014
Andrew Godfrey:

> 1) A function annotation that means "I will call myself
> recursively, and when I do, I expect the tail recursion
> optimization." I have seen code which allocates something big on
> the stack and depends on the optimization. So this intent should
> be expressible.

A @tailrec annotation seems good, and will improve the functional usages of D. It should stop compilation with a error if the function doesn't call itself or if the compiler is not able to remove the recursive call. This means it has to be fully enforced.


> 2) Annotations about when a function does not expect re-entrancy
> to be possible based on call-graph analysis.

I don't understand. Assuming I know this (http://en.wikipedia.org/wiki/Reentrancy_%28computing%29 ) can you show an example?

Bye,
bearophile
July 20, 2014
> Andrew Godfrey:
>
>> 1) A function annotation that means "I will call myself
>> recursively, and when I do, I expect the tail recursion
>> optimization." I have seen code which allocates something big on
>> the stack and depends on the optimization. So this intent should
>> be expressible.
>
> A @tailrec annotation seems good, and will improve the functional usages of D. It should stop compilation with a error if the function doesn't call itself or if the compiler is not able to remove the recursive call. This means it has to be fully enforced.

Perhaps a @cps (or @continuation) annotation is better and more general.

Bye,
bearophile
July 20, 2014
On 7/19/2014 11:06 PM, bearophile wrote:
> A @tailrec annotation seems good, and will improve the functional usages of D.
> It should stop compilation with a error if the function doesn't call itself or
> if the compiler is not able to remove the recursive call. This means it has to
> be fully enforced.

If you want to guarantee replacement of a recursive call with a loop, just write a loop.

July 20, 2014
Walter Bright:

> If you want to guarantee replacement of a recursive call with a loop, just write a loop.

There are cases where a recursive algorithm is nicer. And people that want to use D functionally, may also be used to writing code recursively.

What about the @continuation (http://en.wikipedia.org/wiki/Continuation-passing_style )?

Bye,
bearophile