Issue 22583 - Corrupted function parameters
Summary: Corrupted function parameters
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 Linux
: P2 critical
Assignee: No Owner
URL:
Keywords: backend, wrong-code
Depends on:
Blocks:
 
Reported: 2021-12-11 02:38 UTC by ryuukk_
Modified: 2022-12-17 10:41 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description ryuukk_ 2021-12-11 02:38:02 UTC
I encountered a weird bug

Parameter gets corrupted, the following code works fine with LDC, but with dmd v2.098.0 it doesn't!

https://run.dlang.io/is/T1uuT5

```
import std;

void main()
{
    draw(null, 
            Rectf(0, 0, 256,256),
            64,64,
            0,0,
            128,128,
            1, 1, 0
    );
}

void draw (void* texture,
        Rectf region,
        float x, float y,
        float originX, float originY,
        float width, float height,
	    float scaleX, float scaleY, float rotation) 
{
    assert(texture == null);
    assert(region.x == 0);
    assert(region.y == 0);
    assert(region.width == 256);
    assert(region.height == 256);
}

struct Rectf
{
    float x = 0;
    float y = 0;
    float width = 0;
    float height = 0;
}
```
Comment 1 Dennis 2021-12-12 13:15:29 UTC
This is probably because Rectf is passed by registers, triggering the same bug ashttps://issues.dlang.org/show_bug.cgi?id=22163
Comment 2 Dennis 2021-12-13 13:14:12 UTC
Nevermind, it actually looks like it has to do with the amount of float parameters. This still triggers it:

```
void main()
{
    draw([1, 2, 3], 0, 0, 0, 0, 0, 0, 0, 0, 0);
}

void draw(float[3] region, float, float, float, float, float, float, float, float, float)
{
    assert(region[0] == 1);
    assert(region[1] == 2);
    assert(region[2] == 3);
}
```
But removing any `float` will make it work.
Comment 3 hsteoh 2022-11-01 22:15:40 UTC
Disassembly of _Dmain:

0000000000029a50 <_Dmain>:
   29a50:       55                      push   %rbp
   29a51:       48 89 e5                mov    %rsp,%rbp
   29a54:       48 83 ec 40             sub    $0x40,%rsp
   29a58:       c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%rbp)
   29a5f:       c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)
   29a66:       c7 45 f8 00 00 80 43    movl   $0x43800000,-0x8(%rbp)
   29a6d:       c7 45 fc 00 00 80 43    movl   $0x43800000,-0x4(%rbp)
   29a74:       0f 10 45 f0             movups -0x10(%rbp),%xmm0
   29a78:       0f 29 45 e0             movaps %xmm0,-0x20(%rbp)
   29a7c:       f2 0f 10 45 e0          movsd  -0x20(%rbp),%xmm0
   29a81:       f2 0f 10 4d e8          movsd  -0x18(%rbp),%xmm1  ;<---- this looks wrong
   29a86:       31 c0                   xor    %eax,%eax
   29a88:       48 89 e0                mov    %rsp,%rax
   29a8b:       c7 40 10 00 00 00 00    movl   $0x0,0x10(%rax)
   29a92:       c7 40 08 00 00 80 3f    movl   $0x3f800000,0x8(%rax)
   29a99:       c7 00 00 00 80 3f       movl   $0x3f800000,(%rax)
   29a9f:       31 c0                   xor    %eax,%eax
   29aa1:       89 c7                   mov    %eax,%edi
   29aa3:       f3 0f 10 1d 55 a5 05    movss  0x5a555(%rip),%xmm3        # 84000 <_fini+0xc24>
   29aaa:       00 
   29aab:       0f 57 ed                xorps  %xmm5,%xmm5
   29aae:       f3 0f 10 3d 4e a5 05    movss  0x5a54e(%rip),%xmm7        # 84004 <_fini+0xc28>
   29ab5:       00 
   29ab6:       0f 28 d3                movaps %xmm3,%xmm2
   29ab9:       0f 28 e5                movaps %xmm5,%xmm4
   29abc:       0f 28 f7                movaps %xmm7,%xmm6
   29abf:       e8 0c 00 00 00          call   29ad0 <_D4test4drawFPvSQo5RectffffffffffZv>
   29ac4:       31 c0                   xor    %eax,%eax
   29ac6:       48 83 c4 40             add    $0x40,%rsp
   29aca:       5d                      pop    %rbp
   29acb:       c3                      ret
------

Something is fishy with the codegen here.

- The start of the function loads 4 float values (0, 0, 256f (==0x43800000), 256f) onto the stack locations (rbp-10), (rbp-0c), (rbp-8), (rbp-4): this is the initialization of the temporary Rectf.
- Immediately after that, it loads (rbp-10) into xmm0, copies xmm0 to (rbp-20), then (rbp-20) back to xmm0.  Not sure what's the point of this, but it seems to have something to do with data alignment.
- Then it loads (rbp-18) into xmm1: this looks wrong, (rbp-18) has never been initialized up to this point, so this loads a garbage value into xmm1 (this line is marked "this looks wrong" in the listing above).  This appears to be the reason assert(region.y == 0) fails.

Not sure what exactly is going on with the codegen here, but this appears to be the point where the bug happens.
Comment 4 hsteoh 2022-11-01 22:25:02 UTC
Actually nevermind, ignore what I just said. It's doing a float truncation there from xmm0, that's not the bug.  Also, I mixed up the disassembly, the above listing is from LDC, not DMD.
Comment 5 anonymous4 2022-11-02 16:42:25 UTC
Probably something to do with passing float arguments. 8 arguments are passed in registers xmm0 to xmm7, the rest are pushed on stack. So I suppose 8 is the threshold value.