Thread overview
[Issue 15932] Get rid of the implicit slicing of static arrays
Nov 07, 2022
RazvanN
Nov 07, 2022
hsteoh@qfbox.info
Nov 08, 2022
RazvanN
Nov 15, 2022
hsteoh@qfbox.info
Nov 16, 2022
anonymous4
Dec 17, 2022
Iain Buclaw
June 14, 2016
https://issues.dlang.org/show_bug.cgi?id=15932

hsteoh@quickfur.ath.cx changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |hsteoh@quickfur.ath.cx

--
October 04, 2019
https://issues.dlang.org/show_bug.cgi?id=15932

--- Comment #1 from hsteoh@quickfur.ath.cx ---
Explicit code example illustrating this problem:
-----
struct S {
        int[] data;
        this(int[] _data) { data = _data; }
}
S makeS() {
        int[5] data = [ 1, 2, 3, 4, 5 ];
        return S(data);
}
void func(S s) {
        import std.stdio;
        writeln("s.data = ", s.data);
}
void main() {
        S s = makeS();
        func(s);
}
-----

Expected output:
-----
s.data = [1, 2, 3, 4, 5]
-----

Actual output (YMMV, depends on details of stack implementation on your
platform):
-----
s.data = [-580467872, 32764, 1617267003, 21973, 5]
-----

--
November 07, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

RazvanN <razvan.nitu1305@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |razvan.nitu1305@gmail.com
         Resolution|---                         |FIXED

--- Comment #2 from RazvanN <razvan.nitu1305@gmail.com> ---
If you annotate the functions with @safe then you get:

test.d(9): Deprecation: reference to local variable `data` assigned to non-scope parameter `_data` calling `this`

I think that having the compiler automatically slice your static arrays is actually quite nice as you have to type less. The fact that you can escape a pointer to an expired stack frame is something that @safe and scope should deal with. Still, in system code this should be perfectly fine.

Closing this as WORKSFORME.

--
November 07, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

hsteoh@qfbox.info changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|FIXED                       |---

--- Comment #3 from hsteoh@qfbox.info ---
(In reply to RazvanN from comment #2)
> If you annotate the functions with @safe then you get:
> 
> test.d(9): Deprecation: reference to local variable `data` assigned to non-scope parameter `_data` calling `this`

That's good to know.


> I think that having the compiler automatically slice your static arrays is actually quite nice as you have to type less.

I disagree, the compiler implicitly slicing your static arrays for you has the same sort of issues as implicit constructions in C++: they tend to turn up where they are unexpected and cause problems.


> The fact that you can escape a
> pointer to an expired stack frame is something that @safe and scope should
> deal with. Still, in system code this should be perfectly fine.

How can escaping a pointer to an expired stack frame ever be fine??  That is never OK and should not be allowed in the language. At least, not implicitly. If you want to explicitly escape a reference to a local static array, you should be forced to explicitly slice it, not have the compiler silently insert it for you.

--
November 08, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

--- Comment #4 from RazvanN <razvan.nitu1305@gmail.com> ---
(In reply to hsteoh from comment #3)
> (In reply to RazvanN from comment #2)
> > If you annotate the functions with @safe then you get:
> > 
> > test.d(9): Deprecation: reference to local variable `data` assigned to non-scope parameter `_data` calling `this`
> 
> That's good to know.
> 
> 
> > I think that having the compiler automatically slice your static arrays is actually quite nice as you have to type less.
> 
> I disagree, the compiler implicitly slicing your static arrays for you has the same sort of issues as implicit constructions in C++: they tend to turn up where they are unexpected and cause problems.
> 
> 
> > The fact that you can escape a
> > pointer to an expired stack frame is something that @safe and scope should
> > deal with. Still, in system code this should be perfectly fine.
> 
> How can escaping a pointer to an expired stack frame ever be fine??  That is never OK and should not be allowed in the language. At least, not implicitly. If you want to explicitly escape a reference to a local static array, you should be forced to explicitly slice it, not have the compiler silently insert it for you.

What I meant was that there are situations where implicit slicing of static arrays is actually desirable. For example, the standard library can implement functions that take dynamic arrays and the user can conveniently use static arrays to call those functions.  In most situations that will not lead to memory corruption and inexperienced users can have a much smoother experience.

Also, the plan is to have DIP1000 and @safe by default, so the situations where automatically slicing a dynamic array may lead to escaping of pointers to expired stack frames are going to get caught automatically by default.

If we go down the path to deprecate this behavior we are just going to cause annoyances for less experienced users for no apparent gain.

--
November 15, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

--- Comment #5 from hsteoh@qfbox.info ---
I don't see what's so hard about adding `[]` to a static array before passing it to Phobos.  Even in generic code where you could argue that the incoming type could be either static or dynamic array, you can still write `[]` and it would still work (a slice of a dynamic array is still the same dynamic array, there is no problem there).

This is what Andrei complained about, we bend over backwards to support use cases that weren't intended to be supported, and pretty soon we end up with a ridiculous amount of cruft that didn't even need to be there in the first place. Asking the user to write 2 extra characters is a much simpler and better solution than introducing silent ways to shoot themselves in the foot because they didn't realize what was happening under the hood.  I have been bitten by this specific issue (implicit conversion of static array to dynamic) more than once, the headache in debugging the issue -- because it's implicit and therefore hard to find -- is so not worth the non-existent "cost" of writing two extra characters.  I would have much preferred that the compiler refused to compile the code to bring my attention to the fact that I'm dealing with a static array, than to silently accept static arrays with unexpected semantics that lead to bugs down the road.

--
November 16, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

--- Comment #6 from anonymous4 <dfj1esp02@sneakemail.com> ---
AIU this issue is inspired by std.digest design. You can always have error prone interface and if std.digest is too error prone for intended users, it's just wrong design and should have a safer interface: either take the result storage as an argument or return a heap allocated array or return a value type that will require explicit slicing.

--
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=15932

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P1                          |P4

--