vector::resize causes floating point exception  
Author Message
Daniel_Smith





PostPosted: Visual C++ General, vector::resize causes floating point exception Top

Hello,

I'm hoping for a reality check here. The following program generates a floating point exception in the vector::resize call. I compiled it under VC 2005 using the command line in the comment below.

I've disassembled the executable and found that vector::resize creates a default Point object which is then copied to the new empty elements at the end of the vector. But note that the Point constructor doesn't initialize the x and y members. This means the bits are garbage, and vector::resize will copy the garbage to the new elements. This is no biggie because I don't use the uninitialized elements.

However, the problem is that the compiler uses the floating point processor to copy the doubles. When garbage is loaded into the FPU register, it throws an exception.

One more thing - if I turn off the -O2 switch (optimizations) it works fine.

Maybe this is just an optimizer bug, but I wanted to double check that I wasn't overlooking something.

Thanks for any help,

Dan

// Compile with: cl -EHsc -O2 resize.cpp

#include <float.h>

#include <vector>

class Point

{

public:

double x;

double y;

// No initialization for performance

Point() {}

// Copy constructor

Point(const Point& p): x(p.x), y(p.y) {}

};

void main()

{

// Enable floating point exceptions

int cw = _controlfp(0, 0);

cw &= ~(EM_OVERFLOW | EM_UNDERFLOW | EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID);

_controlfp(cw, MCW_EM);

std::vector<Point> points;

points.resize(4); // <-- crash here

}



Visual C++12  
 
 
einaros





PostPosted: Visual C++ General, vector::resize causes floating point exception Top

I feel that this is borderlining expected program flow.

You are controlling the strictness of floating-point behavior, and provide a class which doesn't initialize the values properly. The only three paths the application compilation and run can follow, as I see it, is:

  1. Verification at compile time that the floating point value isn't garbage. Possible in some cases, but would lead to complex machine code and likely troublesome optimization.
  2. Verification at runtime that a floating point value isn't garbage; which would imply an otherwise unwanted performance cost.
  3. Throw an exception, as you instruct it to.

#3 simply seems like the higher road to me.

If you feel that the issue is a showstopper for you, you can report it at http://connect.microsoft.com, but I'm anything but certain that it's something that they'll fix



 
 
Sarath.





PostPosted: Visual C++ General, vector::resize causes floating point exception Top

i could not find any bug in the Visual C++ 7.1 and Visual C++ 6.0.

Seems Einar's comment is valid.


 
 
Daniel_Smith





PostPosted: Visual C++ General, vector::resize causes floating point exception Top

Thanks for the responses.

So to summarize:

  1. The MS STL is using the copy constructor to implement the resize operation
  2. The compiler is using the FPU registers to copy floating point values (when optimizations are turned on).

So this seems to imply that any class that uses floating point MUST initialize the values to something in the constructor - even if the class and code are careful to never use an uninitialized object. This is a rule I don't recall ever seeing before and will affect a lot of code that assumes data members will be set later on before being used.

Keep in mind that the only thing odd about my code example is that I explicitly enabled FP exceptions. We have found that there are printer drivers that sometimes do this on user machines, so even if your code doesn't do it on purpose, it doesn't mean a driver or injected DLL won't. The end result is that the user will be running with FP exceptions enabled, and anything that copies an unintialized FP value will cause a crash. And the MS STL with optimizations enabled will do exactly that.

How could this have been avoided I'm not an STL expert, but perhaps resize should have used placement new to construct the new elements at the end of the vector (rather than using the copy constructor). Or perhaps the compiler shouldn't be using the FPU registers to copy values (use the integer registers instead).

Thanks,

Dan


 
 
einaros





PostPosted: Visual C++ General, vector::resize causes floating point exception Top

The MS STL is using the copy constructor to implement the resize operation

Yes.

The compiler is using the FPU registers to copy floating point values (when optimizations are turned on).

Yes.

So this seems to imply that any class that uses floating point MUST initialize the values to something in the constructor - even if the class and code are careful to never use an uninitialized object. This is a rule I don't recall ever seeing before and will affect a lot of code that assumes data members will be set later on before being used.

When you configure the floating point exceptions, for e.g. underflows, you are likely to run into problems when the fpu registers are filled with garbage. If you avoid using controlfp, you won't have to initialize your variables. Whether or not it is guaranteed to stay this way, I couldn't say.

Keep in mind that the only thing odd about my code example is that I explicitly enabled FP exceptions. We have found that there are printer drivers that sometimes do this on user machines, so even if your code doesn't do it on purpose, it doesn't mean a driver or injected DLL won't. The end result is that the user will be running with FP exceptions enabled, and anything that copies an unintialized FP value will cause a crash. And the MS STL with optimizations enabled will do exactly that.

I still don't think this can be blamed on the STL implementation. Any use of implicit copy constructors or assignment operators (including the construction of temporaries) will cause the same crash, granted that 1. floating points go by uninitialized, and 2. fp exceptions are switched on.

How could this have been avoided I'm not an STL expert, but perhaps resize should have used placement new to construct the new elements at the end of the vector (rather than using the copy constructor). Or perhaps the compiler shouldn't be using the FPU registers to copy values (use the integer registers instead).

I'm not sure there's an ideal solution to the problem, except being conscious about the design choices.

  • Placement new wouldn't help at all, as it'd end up calling the same copy constructor.
  • Not using the FPU registers would have a performance impact.

In either case, it's good practice to initialize variables with propervalues, and provide an explicit copy ctor and assignment operator if the implementation needs it. Other scenarios, such as with classes containing dynamically allocated pointer members, also require an explicit ctor/oper, so the concept shouldn't be a new one.