1

I have spent 2 days chasing an issue involving C++ container, std::list, and C-Style structs. Is the following undefined behavior (Note the type for the std::list parameter)?

#include <list>
#include <iostream>

using std::cout;
using std::endl;

struct Point_Struct
{
  int x;
  int y;
};

typedef struct Point_Struct Point;

int main()
{
  std::list<Point> line;
  Point p;
  p.x = 3;
  p.y = 10;
  line.push_back(p);

  cout << "Size of container: " << line.size() << "\n";

  //  Here's the issue:
  line.pop_back();

  //  The size should be zero.
  cout << "Size of container after pop_back(): " << line.size() << "\n";

  return 0;
}

I ran this on Visual Studio 2017 and I get an exception error, 0xC0000005, (memory access) on the call to pop_back.

The exception is also thrown on any method that changes the ordering of the items in the list, such as assignment and sort.

If I change the type of line to std::list<Point_Struct>, there are no exceptions thrown.

Note: The issue was found in a larger program. The code above illustrates the root cause of the issue: std::list<typedef struct> vs. std::list<struct>

Note: The exception is thrown in VS2017 debug mode but not in release mode.

Sorry, but multiple questions follow:

  1. Is there anything in standard C++ (11 or later) declaring undefined behavior for using a typedef instead of a struct as the template parameter for std::list?

  2. Would this be a Visual Studio bug?

I haven't tried on G++ or other compilers.

Edit 1: VS2017 version info
Microsoft Visual Studio Professional 2017
Version 15.9.14
Installed product: Visual C++ 2017 - 00369-60000-00001-AA071

Compilation Info
Configuration: Debug
Platform: Win32
Warning Level: Level3 (/W3)
Optimization: Disabled (/Od)
Enable C++ Exception: Yes (/EHsc)
Basic Runtime Checks: Both (/RTC1)
Disable Language Extensions: No
Conformance mode: No

Platform
Platform: Windows 7

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • 6
    Don't bother trying it on other toolchains. It will work. There's nothing fatal about that code (except, apparently, using VS2017 to build+run it). Not surprisingly, I also have no issue with this on VS2015u3. Curiosity is killing me. What happens when you use `using Point = struct Point_Struct;` It should be synonymous behavior (broken or not). Regardless, that smells like a bug if that code really does repro on your rig. – WhozCraig Aug 13 '19 at 22:07
  • 1
    Also on MSVC 2019, 16.2.2 no problem in x86 or x64 debug – CuriouslyRecurringThoughts Aug 13 '19 at 22:10
  • What compiler flags are you using, and which specific version of the compiler? – 1201ProgramAlarm Aug 13 '19 at 22:10
  • 3
    Before we get carried away, has anyone actually reproduced this with VS2017? –  Aug 13 '19 at 22:18
  • I added version details and compilation settings. – Thomas Matthews Aug 13 '19 at 22:21
  • With [`std::stack`, this can be UB](https://stackoverflow.com/a/57387995/10957435) if you're not careful. Maybe you're finding yourself in a similar situation? –  Aug 13 '19 at 22:26
  • @Chipster Nowhere does the code mention std::stack. Before people start coming up with daft theories like this could someone actually confirm that this can be reproduced with VS2017. –  Aug 13 '19 at 22:27
  • 1
    @Chipster: The Original Author used `std::list`. I would not change the container to `std::stack` because that changes the order of the items. If any change, I would switch to `std::vector`. – Thomas Matthews Aug 13 '19 at 22:28
  • @NeilButterworth No, but I'm saying that if the larger program tries to to something bad like pop from an empty list, it may be similar to the linked question. –  Aug 13 '19 at 22:29
  • @Chipster According to the OP, *this code* produces the stated problem. Specifically, *"I ran this on Visual Studio 2017 and I get an exception error"* . Therefore, no speculation of the larger problem is required. Frankly, I cannot see how this is *not* a tool chain defect. Either that or the OP's VS2017 install is polluted by lord-knows-what. – WhozCraig Aug 13 '19 at 22:48
  • 2
    just ran in on this with no problems. Version 15.9.14 Installed product: Visual C++ 2017 - 00369-60000-00001-AA565 – doug Aug 13 '19 at 22:50
  • Suggest debugging side by side with another VS2017 on a clean install. Something appears specific to that installation. I hate when this happens and it's been a long time. But worth it to track down. – doug Aug 13 '19 at 23:09
  • 1
    No Problems on VS2017 - C/C++ Optimizing Compiler Version 19.16.27032.1 using `cl /nologo /W3 /Ox /EHsc /Foobj/list_point.cpp /Febin/list_point.cpp /Tp list_point.cpp` the output is as expected. (no warnings or errors) – David C. Rankin Aug 13 '19 at 23:13
  • I checked with VS Installer and there are no updates. – Thomas Matthews Aug 13 '19 at 23:15
  • I had a VS update today. to 15.9.15. (of course I only boot W10 to answer questions like this -- so it could be from several days ago...) – David C. Rankin Aug 13 '19 at 23:15
  • If you want another data-point, it also compiles and runs fine using VS10 from the Win7_SDK as well with the same command line, e.g. extensions corrected from above, `cl /nologo /W3 /Ox /EHsc /Foobj/list_point /Febin/list_point /Tp list_point.cpp` (they were informational output from a batch file I use that was using `%~1` instead of `%~n1` to output the object and executable filenames -- corrected) – David C. Rankin Aug 14 '19 at 02:09
  • This code works for me as well. I could help diagnose this problem more deeply at an assembly language level, but it'd require you to send me the .exe and .obj files that got made from the above source code. I would definitely try doing a clean build of this as well. (Also, is this x86 or x64?) – Myria Aug 14 '19 at 02:13

1 Answers1

-1

I compiled and ran your code with g++ 11 in Eclipse (Ubuntu 18) and it worked perfectly,

Output:

Size of container: 1
Size of container after pop_back(): 0

Have you tried/is it possible to swap typedef for using? This might fix it:

#include <list>
#include <iostream>

using std::cout;
using std::endl;

struct Point_Struct
{
  int x;
  int y;
};

using Point = Point_Struct;

int main()
{
  std::list<Point> line;
  Point p;
  p.x = 3;
  p.y = 10;
  line.push_back(p);

  cout << "Size of container: " << line.size() << "\n";

  //  Here's the issue:
  line.pop_back();

  //  The size should be zero.
  cout << "Size of container after pop_back(): " << line.size() << "\n";

  return 0;
}
Alexandre Senges
  • 1,474
  • 1
  • 13
  • 22