none
Incorrect code generated for std::array::operator= in VC2010 SP1

    Question

  • I'm reporting this bug here because Submit Feedback form doesn't accept VC2010 issues.

    My problem happens in release Win32 build, compiler switches are:

    /Zi /nologo /W3 /WX /MP /O2 /Oi /Oy- /GL /D "WIN32" /D "_SCL_SECURE_NO_WARNINGS"  /D "NDEBUG" /D "_WINDOWS" /D "_VC80_UPGRADE=0x0710" /D "_WIN32" /D "_SECURE_SCL=0" /D "_HAS_ITERATOR_DEBUGGING=0" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /GF /Gm- /EHsc /MD /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /openmp /Gd /wd"4702" /analyze- /errorReport:queue

    The minimal code snippet which reproduces the bug:

    //////////////////////////////////////////////////////////////////////////
    struct Point
      {
      double m_value[3];
    
      Point& operator=(const Point& i_point)
        {
        for(unsigned i=0;i<3;i++)
          m_value[i] = i_point.m_value[i];
    
        return *this;
        }
      };
    
    //////////////////////////////////////////////////////////////////////////
    struct Foo
      {
      double m1;
      Point m2;
      };
    
    //////////////////////////////////////////////////////////////////////////
    typedef std::array<Foo, 5> ArrFoo;
    
    void MakeCopy(ArrFoo& o_y, const ArrFoo& i_x)
      {
      o_y = i_x; // BUG!
      }
    
    void ReproduceBug()
      {
      ArrFoo x, y;
    
      MakeCopy(y, x);
      }

    The assignment in the line marked "BUG!" corrupts the data in the array.

    Looking into the assembly code shows the reason (notice wrong offsets at addresses 0FD827DD, 0FD827F5  and 0FD8281C):

    std::tr1::array<Foo,5>::operator=:
    0FD827A0  fld         qword ptr [ecx]  
    0FD827A2  fstp        qword ptr [eax]  
    0FD827A4  fld         qword ptr [ecx+8]  
    0FD827A7  fstp        qword ptr [eax+8]  
    0FD827AA  fld         qword ptr [ecx+10h]  
    0FD827AD  fstp        qword ptr [eax+10h]  
    0FD827B0  fld         qword ptr [ecx+18h]  
    0FD827B3  fstp        qword ptr [eax+18h]  
    0FD827B6  fld         qword ptr [ecx+20h]  
    0FD827B9  fstp        qword ptr [eax+20h]  
    0FD827BC  fld         qword ptr [ecx+28h]  
    0FD827BF  fstp        qword ptr [eax+28h]  
    0FD827C2  fld         qword ptr [ecx+30h]  
    0FD827C5  fstp        qword ptr [eax+30h]  
    0FD827C8  fld         qword ptr [ecx+38h]  
    0FD827CB  fstp        qword ptr [eax+38h]  
    0FD827CE  fld         qword ptr [ecx+40h]  
    0FD827D1  fstp        qword ptr [eax+40h]  
    0FD827D4  fld         qword ptr [ecx+48h]  
    0FD827D7  fstp        qword ptr [eax+48h]  
    0FD827DA  fld         qword ptr [ecx+50h]  
    0FD827DD  fstp        qword ptr [eax+30h]  
    0FD827E0  fld         qword ptr [ecx+58h]  
    0FD827E3  fstp        qword ptr [eax+58h]  
    0FD827E6  fld         qword ptr [ecx+60h]  
    0FD827E9  fstp        qword ptr [eax+60h]  
    0FD827EC  fld         qword ptr [ecx+68h]  
    0FD827EF  fstp        qword ptr [eax+68h]  
    0FD827F2  fld         qword ptr [ecx+70h]  
    0FD827F5  fstp        qword ptr [eax+30h]  
    0FD827F8  fld         qword ptr [ecx+78h]  
    0FD827FB  fstp        qword ptr [eax+78h]  
    0FD827FE  fld         qword ptr [ecx+80h]  
    0FD82804  fstp        qword ptr [eax+80h]  
    0FD8280A  fld         qword ptr [ecx+88h]  
    0FD82810  fstp        qword ptr [eax+88h]  
    0FD82816  fld         qword ptr [ecx+90h]  
    0FD8281C  fstp        qword ptr [eax+30h]  
    0FD8281F  fld         qword ptr [ecx+98h]  
    0FD82825  fstp        qword ptr [eax+98h]  
    0FD8282B  ret 

    After swapping the members of struct Foo

    struct Foo
      {
      Point m2;
      double m1;
      };

    the bug disappears because the correct code is generated:

    std::tr1::array<Foo,5>::operator=:
    0FFA27A0  fld         qword ptr [ecx]  
    0FFA27A2  fstp        qword ptr [eax]  
    0FFA27A4  fld         qword ptr [ecx+8]  
    0FFA27A7  fstp        qword ptr [eax+8]  
    0FFA27AA  fld         qword ptr [ecx+10h]  
    0FFA27AD  fstp        qword ptr [eax+10h]  
    0FFA27B0  fld         qword ptr [ecx+18h]  
    0FFA27B3  fstp        qword ptr [eax+18h]  
    0FFA27B6  fld         qword ptr [ecx+20h]  
    0FFA27B9  fstp        qword ptr [eax+20h]  
    0FFA27BC  fld         qword ptr [ecx+28h]  
    0FFA27BF  fstp        qword ptr [eax+28h]  
    0FFA27C2  fld         qword ptr [ecx+30h]  
    0FFA27C5  fstp        qword ptr [eax+30h]  
    0FFA27C8  fld         qword ptr [ecx+38h]  
    0FFA27CB  fstp        qword ptr [eax+38h]  
    0FFA27CE  fld         qword ptr [ecx+40h]  
    0FFA27D1  fstp        qword ptr [eax+40h]  
    0FFA27D4  fld         qword ptr [ecx+48h]  
    0FFA27D7  fstp        qword ptr [eax+48h]  
    0FFA27DA  fld         qword ptr [ecx+50h]  
    0FFA27DD  fstp        qword ptr [eax+50h]  
    0FFA27E0  fld         qword ptr [ecx+58h]  
    0FFA27E3  fstp        qword ptr [eax+58h]  
    0FFA27E6  fld         qword ptr [ecx+60h]  
    0FFA27E9  fstp        qword ptr [eax+60h]  
    0FFA27EC  fld         qword ptr [ecx+68h]  
    0FFA27EF  fstp        qword ptr [eax+68h]  
    0FFA27F2  fld         qword ptr [ecx+70h]  
    0FFA27F5  fstp        qword ptr [eax+70h]  
    0FFA27F8  fld         qword ptr [ecx+78h]  
    0FFA27FB  fstp        qword ptr [eax+78h]  
    0FFA27FE  fld         qword ptr [ecx+80h]  
    0FFA2804  fstp        qword ptr [eax+80h]  
    0FFA280A  fld         qword ptr [ecx+88h]  
    0FFA2810  fstp        qword ptr [eax+88h]  
    0FFA2816  fld         qword ptr [ecx+90h]  
    0FFA281C  fstp        qword ptr [eax+90h]  
    0FFA2822  fld         qword ptr [ecx+98h]  
    0FFA2828  fstp        qword ptr [eax+98h]  
    0FFA282E  ret 

    Is that a known issue? Is there a workaround for it?

    Andrey



    • Edited by Andy_s73 Monday, July 23, 2012 6:07 AM
    Tuesday, July 10, 2012 3:37 PM

Answers

  • This is an optimizer bug that doesn't involve std::array:

    C:\Temp>type meow.cpp
    #include <stdio.h>
    
    struct Point {
        double dbls[3];
    
        Point& operator=(const Point& other) {
            for (int i = 0; i < 3; ++i) {
                dbls[i] = other.dbls[i];
            }
    
            return *this;
        }
    };
    
    struct Foo {
        double db;
        Point pt;
    };
    
    struct Bar {
        Foo foos[5];
    };
    
    int main() {
        Bar x = { {
            { 50, { { 60, 70, 80 } } },
            { 51, { { 61, 71, 81 } } },
            { 52, { { 62, 72, 82 } } },
            { 53, { { 63, 73, 83 } } },
            { 54, { { 64, 74, 84 } } }
        } };
    
        Bar y = { };
    
        y = x;
    
        for (int i = 0; i < 5; ++i) {
            printf("%f %f %f %f\n",
                y.foos[i].db,
                y.foos[i].pt.dbls[0],
                y.foos[i].pt.dbls[1],
                y.foos[i].pt.dbls[2]
            );
        }
    }
    
    C:\Temp>cl
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    usage: cl [ option... ] filename... [ /link linkoption... ]
    
    C:\Temp>cl /EHsc /nologo /W4 /MT meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    
    C:\Temp>cl /EHsc /nologo /W4 /MT /O2 meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 74.000000 81.000000
    52.000000 62.000000 0.000000 82.000000
    53.000000 63.000000 0.000000 83.000000
    54.000000 64.000000 0.000000 84.000000

    And it appears to be fixed in VC11:

    C:\Temp>cl
    Microsoft (R) C/C++ Optimizing Compiler Version 17.00.50622 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    usage: cl [ option... ] filename... [ /link linkoption... ]
    
    C:\Temp>cl /EHsc /nologo /W4 /MT meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    
    C:\Temp>cl /EHsc /nologo /W4 /MT /O2 meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    

    If you can still repro this with VC11 RC, let me know (stl@microsoft.com) and I'll send it to the optimizer team.
    • Proposed as answer by Helen Zhao Wednesday, July 18, 2012 3:02 AM
    • Marked as answer by Andy_s73 Monday, July 23, 2012 6:06 AM
    Tuesday, July 10, 2012 11:23 PM

All replies

  • I'll see if I can draw Stephen Lavavej's eyes (Microsoft) to your post. I'm not sure if this falls into his department or not.
    Tuesday, July 10, 2012 8:38 PM
  • This is an optimizer bug that doesn't involve std::array:

    C:\Temp>type meow.cpp
    #include <stdio.h>
    
    struct Point {
        double dbls[3];
    
        Point& operator=(const Point& other) {
            for (int i = 0; i < 3; ++i) {
                dbls[i] = other.dbls[i];
            }
    
            return *this;
        }
    };
    
    struct Foo {
        double db;
        Point pt;
    };
    
    struct Bar {
        Foo foos[5];
    };
    
    int main() {
        Bar x = { {
            { 50, { { 60, 70, 80 } } },
            { 51, { { 61, 71, 81 } } },
            { 52, { { 62, 72, 82 } } },
            { 53, { { 63, 73, 83 } } },
            { 54, { { 64, 74, 84 } } }
        } };
    
        Bar y = { };
    
        y = x;
    
        for (int i = 0; i < 5; ++i) {
            printf("%f %f %f %f\n",
                y.foos[i].db,
                y.foos[i].pt.dbls[0],
                y.foos[i].pt.dbls[1],
                y.foos[i].pt.dbls[2]
            );
        }
    }
    
    C:\Temp>cl
    Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    usage: cl [ option... ] filename... [ /link linkoption... ]
    
    C:\Temp>cl /EHsc /nologo /W4 /MT meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    
    C:\Temp>cl /EHsc /nologo /W4 /MT /O2 meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 74.000000 81.000000
    52.000000 62.000000 0.000000 82.000000
    53.000000 63.000000 0.000000 83.000000
    54.000000 64.000000 0.000000 84.000000

    And it appears to be fixed in VC11:

    C:\Temp>cl
    Microsoft (R) C/C++ Optimizing Compiler Version 17.00.50622 for x86
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    usage: cl [ option... ] filename... [ /link linkoption... ]
    
    C:\Temp>cl /EHsc /nologo /W4 /MT meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    
    C:\Temp>cl /EHsc /nologo /W4 /MT /O2 meow.cpp && meow
    meow.cpp
    50.000000 60.000000 70.000000 80.000000
    51.000000 61.000000 71.000000 81.000000
    52.000000 62.000000 72.000000 82.000000
    53.000000 63.000000 73.000000 83.000000
    54.000000 64.000000 74.000000 84.000000
    

    If you can still repro this with VC11 RC, let me know (stl@microsoft.com) and I'll send it to the optimizer team.
    • Proposed as answer by Helen Zhao Wednesday, July 18, 2012 3:02 AM
    • Marked as answer by Andy_s73 Monday, July 23, 2012 6:06 AM
    Tuesday, July 10, 2012 11:23 PM
  • Thank you, Stephan!

    As I'm forced to use VC10, could you please give more information about the exact conditions which trigger the bug?

    Monday, July 23, 2012 6:21 AM