wrong-code if stdcall is applied via template parameters

Bug #1956236 reported by Kevin Puetz
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
gcc-9 (Ubuntu)
Fix Released
Undecided
Unassigned

Bug Description

g++ 9.3.0-17ubuntu1~20.04 miscompiles the following example for x86 (bar_stdcall should pop 4 bytes fewer than an bar_cdecl, as stdcall is callee-cleanup for the argument). To see it in this minimized example one must use `-O0` as it will otherwise be inlined and the calling-convention will no longer be meaningful. Larger examples it can hit with optimizations on.

>>>>>>>>>>>>>>>

// g++-9 -c -O0 simple.cpp -m32
//
// objdump -S simple.o

template<bool bIsStdcall, typename T> struct func_ptr_t;

template<typename T> struct func_ptr_t<false,T> {
 using type = void(*)(T);
};

template<typename T> struct func_ptr_t<true,T> {
#if 1
 using type = void(__attribute__((__stdcall__))*)(T);
#else
 using type = void(__attribute__((__stdcall__))*)(int); // this works, using T is important somehow
#endif
};

#if 1
 using foo_stdcall_ptr = func_ptr_t<true,int>::type;
 using foo_cdecl_ptr = func_ptr_t<false,int>::type;
#else
 using foo_stdcall_ptr = void(__attribute__((__stdcall__))*)(int,int);
 using foo_cdecl_ptr = void(*)(int,int);
#endif

foo_stdcall_ptr foo_stdcall;
foo_cdecl_ptr foo_cdecl;

void bar_stdcall() {
 foo_stdcall(1);
}

void bar_cdecl() {
 foo_cdecl(1);
}

>>>>>>>>>>>>>>>

--- bar_cdecl.S 2021-03-09 00:54:58.404022904 +0000
+++ bar_stdcall.S 2021-03-09 00:52:07.900015002 +0000
@@ -1,15 +1,15 @@
-<bar_cdecl()>:
+<bar_stdcall()>:
    0: f3 0f 1e fb endbr32
    4: 55 push %ebp
    5: 89 e5 mov %esp,%ebp
    7: 83 ec 08 sub $0x8,%esp
- a: e8 fc ff ff ff call 32 <bar_cdecl()+0xb>
+ a: e8 fc ff ff ff call b <bar_stdcall()+0xb>
    f: 05 01 00 00 00 add $0x1,%eax
   14: 8b 80 00 00 00 00 mov 0x0(%eax),%eax
   1a: 83 ec 0c sub $0xc,%esp
   1d: 6a 01 push $0x1
   1f: ff d0 call *%eax
- 21: 83 c4 10 add $0x10,%esp
+ 21: 83 c4 0c add $0xc,%esp
   24: 90 nop
   25: c9 leave
   26: c3 ret
```

Upstream gcc-9.3.0 does not have this bug (See https://godbolt.org/z/vK3TdM318), but 9.4.0, 10.0, and 10.1 do). The regression seems to have happened upstream in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90750 - https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=aa988998be8f85334665a6b049d5d9139408c250 - which ubuntu has backported into git-updates.patch (it's in in gcc-9_9.3.0-17ubuntu1~20.04.debian.tar.xz, I have not pinned down when ubuntu picked this up). The regression was fixed in 10.2 by https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95222 - https://gcc.gnu.org/git/?p=gcc.git;a=commit;efdbd4fbea08005091e490ec3f9972aa9c946374 and https://gcc.gnu.org/git/?p=gcc.git;a=commit;0c473d8f32510fcc96d584ee5099b856cfd3d8d6).

I don't think it was realized (when the was found/fixed upstream) that it could also cause wrong-code, so I'm just posting this to make you aware that ubuntu has backported a regression and not the fix. I assume you'll want to align with upstream on whether gcc-9 branch ends up getting this fixed or not.

Revision history for this message
Matthias Klose (doko) wrote :

9.4.0 and 10.5.0 have been backported to 20.04 LTS

Changed in gcc-9 (Ubuntu):
status: New → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.