D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 16408 - [REG2.065] left-to-right order of evaluation of function arguments not consistently followed
Summary: [REG2.065] left-to-right order of evaluation of function arguments not consis...
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 All
: P1 regression
Assignee: No Owner
URL:
Keywords: wrong-code
: 17406 (view as issue list)
Depends on:
Blocks:
 
Reported: 2016-08-21 08:14 UTC by Matt Jones
Modified: 2017-08-07 13:15 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Matt Jones 2016-08-21 08:14:16 UTC
This program prints WASD in debug mode as expected, but prints DDDD in release mode. My guess is std.conv.to!string is failing with char* for some reason.

DMD 2.071.1 on Linux and Windows 10.

Works as expected:
dub run --arch=x86_64 --build=debug

Wrong output:
dub run --arch=x86_64 --build=release

// maid.d
import std.stdio;
import std.string;
import std.conv;
import derelict.sdl2.sdl;


int main() {
	DerelictSDL2.load(SharedLibVersion(2, 0, 2));

	string footer = "%s%s%s%s".format(
		to!string(SDL_GetKeyName(SDLK_w)),
		to!string(SDL_GetKeyName(SDLK_a)),
		to!string(SDL_GetKeyName(SDLK_s)),
		to!string(SDL_GetKeyName(SDLK_d)),
	);
	stdout.writeln(footer);

	return 0;
}

// dub.json
{
	"name": "main",
	"targetType": "executable",

	"dependencies": {
		"derelict-sdl2": "~>2.0",
	},

	"sourceFiles": [
		"main.d"
	],
}
Comment 1 Lodovico Giaretta 2016-08-21 10:31:20 UTC
(In reply to Matt Jones from comment #0)
> This program prints WASD in debug mode as expected, but prints DDDD in
> release mode. My guess is std.conv.to!string is failing with char* for some
> reason.
> 
> [...]

Can I ask you to try with `std.string.fromStringz` instead of `std.conv.to!string` ?
This may help find out where the bug is.
Comment 2 Matt Jones 2016-08-21 11:48:48 UTC
Interesting. Changing from std.conv.to!string to std.string.fromStringz returns "DDDD" for both debug and release mode.
Comment 3 ag0aep6g 2016-08-21 12:44:39 UTC
This is triggered by the -inline switch.

This is a regression. With 2.064.2 it prints "WASD" as expected. Since 2.065 it prints "DDDD".

This seems to be related to SDL_GetKeyName reusing the buffer it returns. From its docs [1]:

> Returns a pointer to a UTF-8 string that stays valid at least until the next call to this function.

So when calling SDL_GetKeyName it multiple times, the previous results are strictly invalidated. In practice, they're overwritten with the newest value.

A reduction based on that:

----
import std.stdio;
import std.conv;

char[2] buffer = '\0';

const(char*) SDL_GetKeyName(char k)
{
    buffer[0] = k;
    return buffer.ptr;
}

void main()
{
    /* prints "WASD" or "DDDD" depending on -inline */
    writeln(
        to!string(SDL_GetKeyName('W')),
        to!string(SDL_GetKeyName('A')),
        to!string(SDL_GetKeyName('S')),
        to!string(SDL_GetKeyName('D')),
    );
}
----

That test case works with 2.066 and fails since 2.067. Notice that those are different versions than for the original test case.

A further reduction reveals a wrong-code compiler bug:

----
char[1] SDL_GetKeyName_buffer;

const(char)[] SDL_GetKeyName(char k)
{
    SDL_GetKeyName_buffer[0] = k;
    return SDL_GetKeyName_buffer[];
}

void formatGeneric() {}

void formattedWrite(string strW, string strA)
{
    auto fun = ()@trusted{ return &formatGeneric; }(); /* !? */

    assert(strW == "W", strW); /* passes without -inline, fails with */
    assert(strA == "A");
}

void main()
{
    formattedWrite(
        SDL_GetKeyName('W').idup,
        SDL_GetKeyName('A').idup,
    );
}
----

That one works with 2.065 and fails since 2.066. Yet again other versions.

I'm promoting this to a regression and to a wrong-code compiler bug. When fixing, all test cases should be checked, since they're might be multiple things going on here.


[1] https://wiki.libsdl.org/SDL_GetKeyName
Comment 4 Lodovico Giaretta 2016-08-21 13:03:15 UTC
(In reply to Matt Jones from comment #2)
> Interesting. Changing from std.conv.to!string to std.string.fromStringz
> returns "DDDD" for both debug and release mode.

ag0aep6g's comment (https://issues.dlang.org/show_bug.cgi?id=16408#c3) is correct.

The fact that SDL_GetKeyName always returns the same buffer explains why fromStringz gives the wrong answer in both debug and release.

So I agree that this is a wrong-code bug.
Comment 5 Matt Jones 2016-08-21 13:13:50 UTC
Excellent. Thanks for figuring this out. Now that I know what is wrong, it should be easy to code around.

Thanks.
Comment 6 Walter Bright 2017-04-12 20:46:49 UTC
Compiles and runs fine with HEAD. I don't know when it was fixed.
Comment 7 ag0aep6g 2017-04-12 20:57:40 UTC
(In reply to Walter Bright from comment #6)
> Compiles and runs fine with HEAD. I don't know when it was fixed.

The test cases from comment #3 still fail for me. dmd 15b3ee1 on linux. Did you compile with -inline?
Comment 8 Walter Bright 2017-04-12 21:09:10 UTC
Yes, you're right. It's still a bug. I had failed to specify -inline.
Comment 9 Walter Bright 2017-04-16 03:45:52 UTC
What's going wrong is the compiler is moving expressions with side effects (SDL_GetKeyName('W'), SDL_GetKeyName('A')) to before the function call, which gets the side effects out of order. I seem to recall a PR to do this, I'll have to find it.
Comment 10 Walter Bright 2017-04-16 05:21:20 UTC
Found the PR that introduced the bug:

https://github.com/dlang/dmd/pull/2880
Comment 11 Walter Bright 2017-04-16 08:37:38 UTC
https://github.com/dlang/dmd/pull/6705
Comment 12 github-bugzilla 2017-04-18 01:37:01 UTC
Commits pushed to master at https://github.com/dlang/dmd

https://github.com/dlang/dmd/commit/8325ecd97aa36502bb92484a50513c7631a5bfa1
fix Issue 16408 - [REG2.065] left-to-right order of evaluation of function arguments not consistently followed

https://github.com/dlang/dmd/commit/630831faa508db4c3b937212d6ea3d3959a8387c
Merge pull request #6705 from WalterBright/fix16408

fix Issue 16408 - [REG2.065] left-to-right order of evaluation of fun…
Comment 13 ag0aep6g 2017-05-18 15:16:41 UTC
*** Issue 17406 has been marked as a duplicate of this issue. ***
Comment 14 github-bugzilla 2017-06-17 11:33:55 UTC
Commits pushed to stable at https://github.com/dlang/dmd

https://github.com/dlang/dmd/commit/8325ecd97aa36502bb92484a50513c7631a5bfa1
fix Issue 16408 - [REG2.065] left-to-right order of evaluation of function arguments not consistently followed

https://github.com/dlang/dmd/commit/630831faa508db4c3b937212d6ea3d3959a8387c
Merge pull request #6705 from WalterBright/fix16408
Comment 15 github-bugzilla 2017-08-07 13:15:45 UTC
Commits pushed to newCTFE at https://github.com/dlang/dmd

https://github.com/dlang/dmd/commit/8325ecd97aa36502bb92484a50513c7631a5bfa1
fix Issue 16408 - [REG2.065] left-to-right order of evaluation of function arguments not consistently followed

https://github.com/dlang/dmd/commit/630831faa508db4c3b937212d6ea3d3959a8387c
Merge pull request #6705 from WalterBright/fix16408