Thread overview
array/Array: "hard" bounds checking
Feb 22, 2018
kdevel
Feb 22, 2018
TheFlyingFiddle
Feb 22, 2018
bauss
Feb 22, 2018
ag0aep6g
Feb 22, 2018
TheFlyingFiddle
February 22, 2018
Is there a D equivalent of the C++ at method? I would like to reformulate

repro2.d
---
void main ()
{
   import std.stdio;
   import std.container;
   import std.range;
   auto z = Array!char();
   z.reserve(0xC000_0000);
   z.capacity.writeln;
   z.length.writeln;
   for (uint u = 0; u < 0xC000_0000; ++u)
      z.insert = 'Y';
   int i = -1073741825;
   i.writeln;
   z[i] = 'Q';
   z[i].writeln;
}
---

$ dmd -O -m32 repro2.d
$ ./repro2
3221225472
0
-1073741825
Q

such that it fails like the 64 bit version:

$ dmd -O -m64 repro2.d
$ ./repro2

3221225472
0
-1073741825
core.exception.RangeError@.../dmd2/linux/bin64/../../src/phobos/std/container/array.d(650): Range violation
----------------
??:? _d_arrayboundsp [0x440d22]
.../dmd2/linux/bin64/../../src/phobos/std/container/array.d:650 inout pure nothrow ref @nogc @safe inout(char) std.container.array.Array!(char).Array.opIndex(ulong) [0x43bb0f]
repro2.d:14 _Dmain [0x43afff]

February 22, 2018
On Thursday, 22 February 2018 at 00:34:59 UTC, kdevel wrote:
> Is there a D equivalent of the C++ at method? I would like to reformulate
>
> repro2.d
> ---
> void main ()
> {
>    import std.stdio;
>    import std.container;
>    import std.range;
>    auto z = Array!char();
>    z.reserve(0xC000_0000);
>    z.capacity.writeln;
>    z.length.writeln;
>    for (uint u = 0; u < 0xC000_0000; ++u)
>       z.insert = 'Y';
>    int i = -1073741825;
>    i.writeln;
>    z[i] = 'Q';
>    z[i].writeln;
> }
> ---
>
> $ dmd -O -m32 repro2.d
> $ ./repro2
> 3221225472
> 0
> -1073741825
> Q
>
> such that it fails like the 64 bit version:
>
> $ dmd -O -m64 repro2.d
> $ ./repro2
>
> 3221225472
> 0
> -1073741825
> core.exception.RangeError@.../dmd2/linux/bin64/../../src/phobos/std/container/array.d(650): Range violation
> ----------------
> ??:? _d_arrayboundsp [0x440d22]
> .../dmd2/linux/bin64/../../src/phobos/std/container/array.d:650 inout pure nothrow ref @nogc @safe inout(char) std.container.array.Array!(char).Array.opIndex(ulong) [0x43bb0f]
> repro2.d:14 _Dmain [0x43afff]

Well in a 32bit program the value 0xBFFF_FFFF(-1073741825) is clearly inside the array. The Array class uses an size_t internaly for storing the length/capacity, that is uint in a 32bit program and ulong in a 64bit program. In the 64bit the value (0xFFFF_FFFF_BFFF_FFFF)(-1073741825) is larger than 0xC000_000 so it will be out of bounds in this case.

If you want any negative integer to be out of bounds the capacity cannot be larger than 0x7FFF_FFFF in 32bit programs.

But this behavior is strange. Well the really strange/bad part is that it's allowed by the compiler in the first place. I would be very happy if a user was forced to make an explicit cast for int <-> uint conversions. Like we have to do for long -> int conversions. Also signed/unsigned comparisons should be strictly outlawed by the compiler.

Eg:

uint a = 3;
int b = -1;

assert(a > b); //No idea what should happen here.




February 22, 2018
On Thursday, 22 February 2018 at 05:22:19 UTC, TheFlyingFiddle wrote:
>
> Eg:
>
> uint a = 3;
> int b = -1;
>
> assert(a > b); //No idea what should happen here.

This is what happens:

assert(cast(int)a > b);
February 22, 2018
On 02/22/2018 10:39 AM, bauss wrote:
> On Thursday, 22 February 2018 at 05:22:19 UTC, TheFlyingFiddle wrote:
>>
>> Eg:
>>
>> uint a = 3;
>> int b = -1;
>>
>> assert(a > b); //No idea what should happen here.
> 
> This is what happens:
> 
> assert(cast(int)a > b);

Nope. It's `assert(a > cast(uint)b);`.
February 22, 2018
On Thursday, 22 February 2018 at 12:50:43 UTC, ag0aep6g wrote:
> On 02/22/2018 10:39 AM, bauss wrote:
>> On Thursday, 22 February 2018 at 05:22:19 UTC, TheFlyingFiddle wrote:
>>>
>>> Eg:
>>>
>>> uint a = 3;
>>> int b = -1;
>>>
>>> assert(a > b); //No idea what should happen here.
>> 
>> This is what happens:
>> 
>> assert(cast(int)a > b);
>
> Nope. It's `assert(a > cast(uint)b);`.

These two posts kind of proved my point :D. And that is why you should never mix signed and unsigned integers. A good thing is that dscanner static analysis will warn you about this stuff (in simple cases at-least).