Thread overview | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 13, 2020 A strange div bug on Linux x86_64, (both dmd & ldc2): long -5000 / size_t 2 = 9223372036854773308 | ||||
---|---|---|---|---|
| ||||
I post here because I think this bug's impact maybe pretty wide, it's a div bug on Linux x86_64, (both dmd & ldc2). I'm interested in knowing what caused this bug. On Windows, I only tested dmd.exe, it correctly outputs -2500. size_t: because I was taking array length, maybe many people do that too. https://issues.dlang.org/show_bug.cgi?id=21151 import std.stdio; void main() { long a = -5000; size_t b = 2; long c = a / b; writeln(c); } $ dmd divbug.d $ ./divbug 9223372036854773308 $ ldc2 divbug.d $ ./divbug 9223372036854773308 x86_64 x86_64 x86_64 GNU/Linux $ dmd --version DMD64 D Compiler v2.092.0 $ ldc2 --version LDC - the LLVM D compiler (1.21.0): based on DMD v2.091.1 and LLVM 10.0.0 built with LDC - the LLVM D compiler (1.21.0) Default target: x86_64-unknown-linux-gnu Host CPU: bdver2 |
August 13, 2020 Not a bug! :) | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thursday, 13 August 2020 at 07:22:18 UTC, mw wrote: > I post here because I think this bug's impact maybe pretty wide, it's a div bug on Linux x86_64, (both dmd & ldc2). I'm interested in knowing what caused this bug. > > On Windows, I only tested dmd.exe, it correctly outputs -2500. > > > size_t: because I was taking array length, maybe many people do that too. > > > https://issues.dlang.org/show_bug.cgi?id=21151 > > import std.stdio; > > void main() { > long a = -5000; > size_t b = 2; > long c = a / b; > writeln(c); > } > > > $ dmd divbug.d > $ ./divbug > 9223372036854773308 > > > $ ldc2 divbug.d > $ ./divbug > 9223372036854773308 > > > x86_64 x86_64 x86_64 GNU/Linux > > $ dmd --version > DMD64 D Compiler v2.092.0 > > $ ldc2 --version > LDC - the LLVM D compiler (1.21.0): > based on DMD v2.091.1 and LLVM 10.0.0 > built with LDC - the LLVM D compiler (1.21.0) > Default target: x86_64-unknown-linux-gnu > Host CPU: bdver2 "Not a bug." Or rather, same semantics as in C. The division reinterprets a as unsigned, and the result is within the positive range of a long, so it stays positive post-division. #include <stdio.h> void main() { long long int a = -5000; long long unsigned int b = 2; // the expression is unsigned, and reinterpreted as positive signed with the assignment long long int c = a / b; printf("%lli\n", c); // crazy number } |
August 13, 2020 Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thursday, 13 August 2020 at 07:22:18 UTC, mw wrote: > I post here because I think this bug's impact maybe pretty wide, it's a div bug on Linux x86_64, (both dmd & ldc2). I'm interested in knowing what caused this bug. > > On Windows, I only tested dmd.exe, it correctly outputs -2500. > > > size_t: because I was taking array length, maybe many people do that too. > > > https://issues.dlang.org/show_bug.cgi?id=21151 > > import std.stdio; > > void main() { > long a = -5000; > size_t b = 2; > long c = a / b; > writeln(c); > } > > > $ dmd divbug.d > $ ./divbug > 9223372036854773308 > > > $ ldc2 divbug.d > $ ./divbug > 9223372036854773308 > > > x86_64 x86_64 x86_64 GNU/Linux > > $ dmd --version > DMD64 D Compiler v2.092.0 > > $ ldc2 --version > LDC - the LLVM D compiler (1.21.0): > based on DMD v2.091.1 and LLVM 10.0.0 > built with LDC - the LLVM D compiler (1.21.0) > Default target: x86_64-unknown-linux-gnu > Host CPU: bdver2 "Not a bug." Or rather, same semantics as in C. The division reinterprets a as unsigned, and the result is within the positive range of a long, so it stays positive post-division. #include <stdio.h> void main() { long long int a = -5000; long long unsigned int b = 2; // the expression is unsigned, and reinterpreted as positive signed with the assignment long long int c = a / b; printf("%lli\n", c); // crazy number } Whether that is correct is a whole other question. Personally I think it's insane. |
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to FeepingCreature | On Thursday, 13 August 2020 at 07:51:06 UTC, FeepingCreature wrote: > "Not a bug." Or rather, same semantics as in C. The division reinterprets a as unsigned, and the result is within the positive range of a long, so it stays positive post-division. https://issues.dlang.org/show_bug.cgi?id=21151 Let me add all my post together: It can NOT silently do this, at least a warning. BTW, on Windows, dmd correctly output -2500. Just because C/C++ did it doesn't means it's correct. And D supposed to be an improvement of C++. OK, let me write this in this way to show it's impact: ================================== import std.algorithm; import std.stdio; void main() { long[] a = [-5000, 0]; long c = sum(a) / a.length; writeln(c); } ================================== $ ./divbug 9223372036854773308 |
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thursday, 13 August 2020 at 07:56:31 UTC, mw wrote:
> On Thursday, 13 August 2020 at 07:51:06 UTC, FeepingCreature wrote:
>> "Not a bug." Or rather, same semantics as in C. The division reinterprets a as unsigned, and the result is within the positive range of a long, so it stays positive post-division.
>
>
> https://issues.dlang.org/show_bug.cgi?id=21151
>
> Let me add all my post together:
>
> It can NOT silently do this, at least a warning.
>
> BTW, on Windows, dmd correctly output -2500.
>
> Just because C/C++ did it doesn't means it's correct.
>
> And D supposed to be an improvement of C++.
>
>
> OK, let me write this in this way to show it's impact:
> ==================================
> import std.algorithm;
> import std.stdio;
>
> void main() {
> long[] a = [-5000, 0];
> long c = sum(a) / a.length;
> writeln(c);
> }
> ==================================
>
>
> $ ./divbug
> 9223372036854773308
The windows version is probably different because you are building a 32 bit exe and therefore size_t is uint, which will be promoted to long in the division.
If you do a bit of a search on the forums you'll find this issue having come up many times before and you might find those discussions informative.
|
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thursday, 13 August 2020 at 07:56:31 UTC, mw wrote:
> On Thursday, 13 August 2020 at 07:51:06 UTC, FeepingCreature wrote:
>> "Not a bug." Or rather, same semantics as in C. The division reinterprets a as unsigned, and the result is within the positive range of a long, so it stays positive post-division.
>
>
> https://issues.dlang.org/show_bug.cgi?id=21151
>
> Let me add all my post together:
>
> It can NOT silently do this, at least a warning.
>
> BTW, on Windows, dmd correctly output -2500.
>
> Just because C/C++ did it doesn't means it's correct.
>
> And D supposed to be an improvement of C++.
>
>
> OK, let me write this in this way to show it's impact:
> ==================================
> import std.algorithm;
> import std.stdio;
>
> void main() {
> long[] a = [-5000, 0];
> long c = sum(a) / a.length;
> writeln(c);
> }
> ==================================
>
>
> $ ./divbug
> 9223372036854773308
Yes, hence: not a compiler bug, but a spec bug. Implicit conversions should never throw away data, and silently converting from signed to unsigned, especially for a sign-sensitive operation like division, is insane. I'm not saying it's not an issue, I'm saying it should be raised against the spec, not the compiler, which faithfully implements it.
|
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Thursday, 13 August 2020 at 08:07:56 UTC, John Colvin wrote: > The windows version is probably different because you are building a 32 bit exe and therefore size_t is uint, which will be promoted to long in the division. $ /mnt/c/project/dmd2/windows/bin64/dmd.exe --version DMD64 D Compiler v2.092.0-dirty Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved written by Walter Bright > If you do a bit of a search on the forums you'll find this issue having come up many times before and you might find those discussions informative. Sigh, if D continue behave like this, it can hardly be called a C++ improvement. |
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thursday, 13 August 2020 at 08:23:30 UTC, mw wrote: > On Thursday, 13 August 2020 at 08:07:56 UTC, John Colvin wrote: >> The windows version is probably different because you are building a 32 bit exe and therefore size_t is uint, which will be promoted to long in the division. > > $ /mnt/c/project/dmd2/windows/bin64/dmd.exe --version > DMD64 D Compiler v2.092.0-dirty > Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved written by Walter Bright > compiler architecture doesn't imply generated code architecture. E.g. try compiling your file with -m32 or -m64 or -m32mscoff (see https://dlang.org/dmd-windows.html#switch-m32) >> If you do a bit of a search on the forums you'll find this issue having come up many times before and you might find those discussions informative. > > Sigh, if D continue behave like this, it can hardly be called a C++ improvement. D has many differences with C/C++, many of which I would consider an improvement. However, it does not address all of the things that cause difficulty with C/C++. Personally I would love to be able to disallow implicit signed-to-unsigned conversions in almost all cases, but that would be a big breaking change. |
August 13, 2020 Re: Not a compiler bug. | ||||
---|---|---|---|---|
| ||||
Posted in reply to John Colvin | On Thursday, 13 August 2020 at 09:25:07 UTC, John Colvin wrote:
> Personally I would love to be able to disallow implicit signed-to-unsigned conversions in almost all cases, but that would be a big breaking change.
This was broken without even an announcement or discussion (maybe I missed it):
foreach(int ii, val; [1, 2, 3, 4, 5]) {}
Upon compilation, you get a message
Deprecation: foreach: loop index implicitly converted from size_t to int
I had to go back and fix lots of previously working code, even though there was no reason at all that it would ever fail to work correctly. Then there is the move to safe by default. Surely if we can make those changes, we can change the behavior in this case. The output of this program is a serious WTF:
import std;
void main()
{
foreach(int ii, val; [1, 2, 3, 4, 5]) {
writeln(ii);
}
writeln(-5000/[1, 2, 3, 4].length);
}
|
August 13, 2020 Re: A strange div bug on Linux x86_64, (both dmd & ldc2): long -5000 / size_t 2 = 9223372036854773308 | ||||
---|---|---|---|---|
| ||||
Posted in reply to mw | On Thu, Aug 13, 2020 at 07:22:18AM +0000, mw via Digitalmars-d wrote: [...] > void main() { > long a = -5000; > size_t b = 2; > long c = a / b; > writeln(c); > } You're mixing signed and unsigned values. That's generally dangerous territory where integer promotion rules inherited from C/C++ take over and cause sometimes weird effects, like here. Changing integer promotion rules will probably never happen now, because it will cause massive *silent* breakage of existing code. So, in the spirit of defensive programming, I recommend avoiding mixing signed/unsigned values in this way. T -- It said to install Windows 2000 or better, so I installed Linux instead. |
Copyright © 1999-2021 by the D Language Foundation