#1685 Incorrect argument clearance in one of method instances

OTHER
open
nobody
gcc (462)
Bug
later
Known_bugs
False
2015-02-15
2012-12-10
Oleh Derevenko
No

After upgrading to GCC 4.7.2 I'having an issue that release build of my DLL crashes. Debugging shows that this is due to bad code generated by GCC, Alas I can't provide small test case but here is the faulting function fragment itself.
-----------------------
int CProfileGenerator::CalcAccProfile(
pos_type p0,
vel_type v0,
acc_type a0,
jerk_type j,
vel_type vel,
acc_type acc,
CProfile& ret_profile
) const {
time_type t0 = 0.0;
ret_profile.clear(); ret_profile.reserve(10);

vel_type dv = vel-v0;

if (ABS(dv) < m_epsilon_v && ABS(a0) < m_epsilon_a) {
if (dv == 0.0) {
ret_profile.push_back(CProfileStep(0.0, p0, v0, a0, 0.0)); VALIDATEPROFILE(ret_profile);
} else {
acc_type a0 = (dv<0.0)?-1.0:1.0;
time_type dt = ABS(dv);
pos_type p1 = p0 + v0*dt + 0.5*dv*dv;
ret_profile.push_back(CProfileStep(0.0, p0, v0, a0, 0.0)); VALIDATEPROFILE(ret_profile);
ret_profile.push_back(CProfileStep(dt, p1, vel, 0.0, 0.0)); VALIDATEPROFILE(ret_profile);
}
G_BLOG_4("acc profile calc skiped ");
return ret_profile.size();
}
if (v0 < vel) {
acc = ABS(acc);
} else if (v0 == vel) {
acc = -SIGN(a0)*ABS(acc);
} else {
acc = -ABS(acc);
}

if (j == 0.0) {
return InternalAccCalc(t0, p0, v0, 0.0, 0.0, true, true, vel, acc, true, ret_profile);
// <------------------------------ FAULTS DUE TO RETURNING TO ADDRESS 0x00000000 HERE
}
...
-----------------------
Here all the *_type typedefs are doubles and CProfile is std::vector of CProfileStep structure.

I've built library with -fno-inline to be able to see function calls more clearly and here is the problem is assembler code.
-----------------------
Dump of assembler code for function CProfileGenerator::CalcAccProfile(double, double, double, double, double, double, CP
rofileGenerator::CProfile&) const:
0x100622e0 <+0>: push %ebp
0x100622e1 <+1>: mov %ecx,%ebp
0x100622e3 <+3>: push %edi
0x100622e4 <+4>: push %esi
0x100622e5 <+5>: push %ebx
0x100622e6 <+6>: sub $0x14c,%esp
; <------------------------ Initial stack preparation ends here
0x100622ec <+12>: mov 0x160(%esp),%eax
0x100622f3 <+19>: mov 0x190(%esp),%ebx
0x100622fa <+26>: fldl 0x188(%esp)
0x10062301 <+33>: fstpl 0x98(%esp)
...
...
...
0x1006254a <+618>: jbe 0x10062920 <CProfileGenerator::CalcAccProfile(double, double, double, double, double, dou
ble, CProfileGenerator::CProfile&) const+1600>
0x10062550 <+624>: fldl 0x98(%esp)
0x10062557 <+631>: fstpl (%esp)
0x1006255a <+634>: call 0x1005f2e0 <ABS<double>(double const&)>
0x1006255f <+639>: fldl 0xb0(%esp)
0x10062566 <+646>: fldz
0x10062568 <+648>: fld %st(0)
0x1006256a <+650>: fxch %st(2)
0x1006256c <+652>: fucomi %st(2),%st
0x1006256e <+654>: fstp %st(2)
0x10062570 <+656>: jnp 0x10062b00 <CProfileGenerator::CalcAccProfile(double, double, double, double, double, dou
ble, CProfileGenerator::CProfile&) const+2080>
...
...
...
0x10062b00 <+2080>: jne 0x10062580 <CProfileGenerator::CalcAccProfile(double, double, double, double, double, dou
ble, CProfileGenerator::CProfile&) const+672>
0x10062b06 <+2086>: fstp %st(1)
0x10062b08 <+2088>: fxch %st(1)
0x10062b0a <+2090>: fstpl 0x30(%esp)
0x10062b0e <+2094>: mov %ebx,%ecx
0x10062b10 <+2096>: fldl 0x90(%esp)
0x10062b17 <+2103>: mov $0x1,%edx
0x10062b1c <+2108>: mov $0x1,%eax
0x10062b21 <+2113>: fstpl 0x28(%esp)
0x10062b25 <+2117>: fstl 0x20(%esp)
0x10062b29 <+2121>: fstl 0x18(%esp)
0x10062b2d <+2125>: fldl 0x88(%esp)
0x10062b34 <+2132>: fstpl 0x10(%esp)
0x10062b38 <+2136>: fldl 0xc8(%esp)
0x10062b3f <+2143>: fstpl 0x8(%esp)
0x10062b43 <+2147>: fstpl (%esp)
0x10062b46 <+2150>: call 0x10061890 <CProfileGenerator::InternalAccCalc(double, double, double, double, double, bo
ol, bool, double, double, bool, CProfileGenerator::CProfile&) const>

0x10062b4b <+2155>: sub $0x38,%esp <----------------------------------------- THIS COMMAND CORRUPTS STACK POINTER WHICH OTHERWISE WOULD BE VALID

0x10062b4e <+2158>: add $0x14c,%esp
0x10062b54 <+2164>: pop %ebx
0x10062b55 <+2165>: pop %esi
0x10062b56 <+2166>: pop %edi
0x10062b57 <+2167>: pop %ebp
0x10062b58 <+2168>: ret $0x34
-----------------------

It looks like you reuse the same stack area for all the calls and just re-adjust stack pointer back to compensate ret <N> instruction in functions being called. With this, the cause of the problem is the following. It's all about the method CProfileGenerator::InternalAccCalc which is being invoked. In function faulting the method is called 4 times from different execution paths (the first one shown above and the other 3 further in the function). Actually, GCC has generated two instances of CProfileGenerator::InternalAccCalc: at 0x1005aa40 and 0x1005a660, - each of those two instances being called twice. For first instance the stack is adjusted by 0x38 in caller, while for second instance the stack is adjusted by 0x48. However if second instance contains correct "ret 0x48" exit instructions, the first one containg just plain "ret" which causes the stack corruption.
Attached is the method's source and disassembled text of two instances generated.
The instances are invoked as InternalAccCalc(t0, p0, v0, 0.0, 0.0, true, true, vel, acc, true, ret_profile); // #1
InternalAccCalc(t0, p0, v0, a0, j, z1, z2, vel, acc, true, ret_profile); // #1
InternalAccCalc(t0, p0, v0, a0, j, z1, z2, vel, limit_acc1, false, ret_profile); // #2
InternalAccCalc(t0, p0, v0, a0, j, z1, z2, vel, limit_acc2, false, ret_profile); // #2

The GCC was auto-installed by setup application from SourceForge
H:\Projects\FTSI\other\GUI>"c:\Util\MinGW\bin\g++.exe" -v
Using built-in specs.
COLLECT_GCC=c:\Util\MinGW\bin\g++.exe
COLLECT_LTO_WRAPPER=c:/util/mingw/bin/../libexec/gcc/mingw32/4.7.2/lto-wrapper.e
xe
Target: mingw32
Configured with: ../gcc-4.7.2/configure --enable-languages=c,c++,ada,fortran,obj
c,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgo
mp --disable-win32-registry --enable-libstdcxx-debug --disable-build-poststage1-
with-cxx --enable-version-specific-runtime-libs --build=mingw32 --prefix=/mingw
Thread model: win32
gcc version 4.7.2 (GCC)

The file was compiled with following options
g++ -D"USED_LIBS=" -D_NDEBUG -DNDEBUG -DNODEBUG -DNO_EXCEPTIONS -D__STL_THREADS
-D_MT -DUSE_DELPHI_STRINGS -mwindows -mconsole -mthreads -malign-double -Wall -
W -Wno-unused-function -Wno-unused-parameter -O3 -march=i686 -g -DLOGING -D_C
ONSOLE -fno-exceptions -fno-rtti -Woverloaded-virtual -fno-inline ../../shared/pr
ofiles/MoveProfileGenerator.cpp -c -o bin/release/MoveProfileGenerator.obj

Discussion

  • Oleh Derevenko
    Oleh Derevenko
    2012-12-10

    Method source and disassenbler dumps of two instances

     
  • Earnie Boyd
    Earnie Boyd
    2013-01-08

    • status: open --> pending-remind
     
  • Earnie Boyd
    Earnie Boyd
    2013-01-08

    Please file a bug report with GCC see gcc.gnu.org/bugs.html for instructions.

     
  • Oleh Derevenko
    Oleh Derevenko
    2013-01-08

    • status: pending-remind --> open-remind
     
  • Oleh Derevenko
    Oleh Derevenko
    2013-01-08

    I've decided to report it against MinGW because the same source compiled with the same version of compiler and similar options on QNX does not produce this invalid code. How can I prove to GCC developers it's their issue?

     
  • Oleh Derevenko
    Oleh Derevenko
    2013-01-08

    Also, GCC has already release 4.7.3 available. The first thing they'll do is going to be asking me to upgrade to 4.7.3. And I will not be able to do that since MinGW is only 4.7.2 yet.

     
  • Earnie Boyd
    Earnie Boyd
    2013-01-08

    It has to be either GCC or binutils or your source. Since you're stating the stack frame, then we need to eliminate either GCC or binutils.

    If you don't open the bug reports you'll never convince them of a bug. It could be that the bug is yet undiscovered and not in 4.7.3 release or discovered and not in 4.7.3 release. I understand the testing on the current release but it isn't provided to you yet as you already state. That doesn't mean the bug report isn't valuable.

     
  • Oleh Derevenko
    Oleh Derevenko
    2013-01-08

    OK, reported it for GCC. Let's see if I'll be able to win the fight with them. ;)

     
  • Oleh Derevenko
    Oleh Derevenko
    2013-01-08

    And also, sorry - there is n 4.7.3 available for download yet. It's only in their bugtracker that this new version is available for some reason (a beta, perhaps?)

     
  • Earnie Boyd
    Earnie Boyd
    2013-02-04

    Oleh can you please give us the bug report link? TIA

     
  • Earnie Boyd
    Earnie Boyd
    2013-02-04

    • Description has changed:

    Diff:

    --- old
    +++ new
    @@ -1,4 +1,3 @@
    -
     After upgrading to GCC 4.7.2 I'having an issue that release build of my DLL crashes. Debugging shows that this is due to bad code generated by GCC, Alas I can't provide small test case but here is the faulting function fragment itself.
     \-----------------------
     int CProfileGenerator::CalcAccProfile\(
    
    • status: open-remind --> open
    • resolution: --> later
    • category: --> Known_bugs
    • milestone: --> OTHER
     
  • Earnie Boyd
    Earnie Boyd
    2013-02-04

    Can anyone see what changed in the Diff above? If not I need to report a bug to SF.

     
    • Keith Marshall
      Keith Marshall
      2013-02-04

      One empty line removed, apparently.

       
      • Earnie Boyd
        Earnie Boyd
        2013-02-05

        Not by my doing anything. I'll open a support ticket for it just so it's documented for Allura.

         
  • Earnie Boyd
    Earnie Boyd
    2013-02-11

    • type: --> Bug
    • patch_attached: --> False