crash in test suite testKernelInterpolation2D with STLPort : the iterator shouldn't be stored?

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

crash in test suite testKernelInterpolation2D with STLPort : the iterator shouldn't be stored?

marcelloptr
Using QuantLib-1.2.1 with STLPort-5.2.1, compiled under vs2010. Win32.

The test suite run all tests perfectly but one:

1>  unknown location(0): fatal error in "QuantLib::detail::quantlib_test_case(&InterpolationTest::testKernelInterpolation2D)": std::runtime_error: 
      1>D:\Projecs\STLport-5.2.1\stlport\stl/debug/_debug.c(575): STL error : Uninitialized or invalidated (by mutating operation) iterator used

The reason goes deep in the C++ specifications of a copy of an iterator, and probably the use of it in InterpolationTest::testKernelInterpolation2D is incorrect. MS's Dirkumware library probably doesn't crash because it doesn't perform the debug check that STLPort is capable of.

Here's what happens:

void InterpolationTest::testKernelInterpolation2D()
{
    ... // some test code

    KernelInterpolation2D kernel2DEp(xVec1.begin(),xVec1.end(),
                                     yVec1.begin(),yVec1.end(),M1,
                                     &epanechnikovKernel);

    ... // some test code

    // test updating mechanism by changing initial variables
    xVec1.clear();yVec1.clear(); // invalidates iterators of kernel2DEp too

    xVec1+=60.0,95.0,105.0,135.0;
    yVec1+=12.5,13.7,15.0,19.0,26.5,27.5,29.2,36.5;

    kernel2DEp.update(); // <-- crash here.

   ... // some test code
}

KernelInterpolation2D stores the iterators: begin() and end() of xVec1 and yVec1.begin()
in the variables: xBegin_, xEnd_, yBegin_ and yEnd_ of kernel2DEp,
then update() is called from within the KernelInterpolation2D ctor.

Later the iterators of xVec1 and yVec1 are invalidated
xVec1.clear();yVec1.clear();

and this invalidates also the iterators in kernel2DEp because it stored them.

When doing
   xVec1+=60.0,95.0,105.0,135.0;
    yVec1+=12.5,13.7,15.0,19.0,26.5,27.5,29.2,36.5;
we have again a valid begin() iterator for xVec1 and yVec1, but they are not the ones that have been copied into kernel2DEp. (KernelInterpolation2D  keeps a copy of them, not a reference)

This seems logically correct to me, because reinitializing the data in a vector usually requires the allocation of a different memory area, and so the previous copied iterator should be invalid or at least not guaranteed to be valid.

When later we run kernel2DEp.update(); we have of course the crash.


The final answer can be given only by someone who knows well the C++ STL specifications on this, I guess, but I highly doubt that STLPort is wrong on this.


Some considerations:
My overall impression is that the idea of storing those iterators that are used to initialize KernelInterpolation2D is dangerous.
What about passing them as argument every time is needed instead?
Is it necessary to store them? If it is necessary then maybe the function update() that is using them should be made protected: not public:.
I didn't look enough into your (excellent) library to tell.

With Interpolation2D::update() protected the following files wouldn't compile:
extendedblackvariancesurface.cpp(83)
capfloortermvolsurface.cpp(225)
flatextrapolation2d.hpp(76)

If you want to store those pointer and keep update() public, then maybe a public setter for those iterators could be provided and the test made working.

No matter what, to find a way to avoid this problem to the user or a way to check against this incorrect use would be welcome because only STLPort debug seems to warn you against this.