Discussion:
Qwt crash when I try to plot infinity
Peter Nordin
2014-04-23 13:47:10 UTC
Permalink
Hi

I have run into a problem with qwt causing a crash when I "try to plot"
something with value inf.

Basically I get the following error: ASSERT failure in qAllocMore:
"Requested size is to large!" .....

I was able to track down the crash into:
QwtLinearScaleEngine::buildMinorTicks where a for loop never ends.
The reason for it never ending is that earlier in QwtPlot::updateAxes a
calculated "stepSize" turned out to be: -nan(0x8000000000000)
This is caused by my min and max values being [100 inf]
I think its the autoscale function that calculates the stepSize

I am not sure what should really happen when you try to plot something
that is inf, but it would be nice if the scale could handle it without
crashing somehow.

I have made an MinimumWorkingExample that you can find here:
https://www.dropbox.com/sh/v6uiw21pzpxxw9b/PZMTYd348r
It is a modification of the default sinusplot qwt example and it
increases a value until it reaches inf.
Just copy the two files into the sinusplot example directory and then
build and run the example to generate the crash.

Best regards
Peter Nordin
Hendrik Vennekate
2014-04-23 16:05:14 UTC
Permalink
Hi Peter,
Post by Peter Nordin
QwtLinearScaleEngine::buildMinorTicks where a for loop never ends.
The reason for it never ending is that earlier in QwtPlot::updateAxes a
calculated "stepSize" turned out to be: -nan(0x8000000000000)
This is caused by my min and max values being [100 inf]
I think its the autoscale function that calculates the stepSize
Ok, going from there:
If autoScale is not enabled, the problem doesn't occur (ok, that was kinda
obvious).
QwtLinearScaleEngine::autoScale calculates the value of stepSize, as you said,
from [100 inf]. So the obvious goal would be to exclude "inf" values from the
calculation of maxValue. The latter is obtained from the boundingRect of the
plot items a few lines above in QwtPlot::updateAxes(). That one seems to come
from QwtPlotSeriesItem::boundingRect(), which gets it from
QwtSeriesStore<T>::dataRect() (with T = QPointF), which gets it from
QwtSeriesData<T>::boundingRect(). For QwtPlotCurve, if you use
QwtPlotData::setSamples(const QVector...), the "QwtSeriesData<T>* d_series"
(for which that function is called) of QwtSeriesStore<T> will actually be a
QwtPointArrayData object.
The latter only refreshes its boundingRect (d_boundingRect) in
QwtPointArrayData::boundingRect(), if it's width < 0, by calling
qwtBoundingRect(), which in turn calls qwtBoundingRectT<T>() (with T =
QPointF). And that's essentially the end of it, where the inf is included
although it shouldn't (in your case probably down in the last for block, but
I'd suspect that the first one might be equally prone for that if the inf
value is the first value of the series of data points.

Ok, that was a long story of walking throught the code. Now let's see what we
can do about it:
Ultimately, one might probably want to reconsider the handling of inf values
in qwtBoundingRect<T>(). But that's up to Uwe, I'd say.
For a quick fix, there are multiple ways of reimplementing one of the virtual
functions in the walkthrough above, namely:
1) QwtPointArrayData::boundingRect() (i.e. subclass QwtPointArrayData, create
the two constructors, and reimplement boudingRect()). That, however, would
also make it necessary to subclass QwtPlotCurve and work around its
setSamples() functions and/or only use QwtPlotCurve::setData() (which is
actually QwtSeriesStore<QPointF>::setData()) for setting an object of the
subclassed version.
2) Or you could subclass QwtPlotCurve and reimplement boundingRect() there
(inherited from QwtPlotSeriesItem), which would probably be simpler.
3) or reimplement QwtPlotSeriesStore<T>::dataRect() (which would also entail a
myriad of adaptations of other classes as in 1))
4) or QwtPlotSeriesItem::boundingRect() (but that's cumbersome for similar
reasons (interdependencies) as 1) and 3)).
5) or you could implement your own autoScale functionality by reimplementing
one of the functions in QwtPlot involved in this process. This struck me, for
instance, because I've never seen that crash and I think I've seen quite a few
"inf"s -- turns out I had QwtPlot::replot() reimplemented to include my own
version of autoScaling (because it does not include all plot items in the
calculation of the new rectangle).

So, the cleanest choice would probably be 2) (unless I've missed something),
or otherwise probably 5).
Post by Peter Nordin
I am not sure what should really happen when you try to plot something
that is inf, but it would be nice if the scale could handle it without
crashing somehow.
My guess: exclude that particular value?
Post by Peter Nordin
https://www.dropbox.com/sh/v6uiw21pzpxxw9b/PZMTYd348r
Certainly appreciated that, thanks!

I hope that helps, sorry for the long text (but I'm getting lost in the code
here, so the text is actually more my notes), and best wishes,

Hendrik
Uwe Rathmann
2014-04-24 10:39:12 UTC
Permalink
Post by Peter Nordin
I am not sure what should really happen when you try to plot something
that is inf, but it would be nice if the scale could handle it without
crashing somehow.
Well I could add some checks here and there, but without adding sanity
checks for every sample it won't help much.

But these type of checks slow down replotting - something I don't want
to do, considering that we are talking about issues that should be
handled/fixed on application side anyway.

Uwe
Peter Nordin
2014-04-24 11:12:05 UTC
Permalink
Hi Uwe

I see your point, I was just uncertain if Qwt should be able to handle
Infs automatically, since I had seen that working (at least not causing
a crash) before. Most likely auto-scale was not used in those cases.

I also recently saw -Inf working, but I realize now that there is no
such think as -Inf in double, it turns into NaN which seems to work in
the auto-scale calculation.

To Hendrik:

Thank you for a thorough reply.
As you said, 2) or 5) seems to be the reasonable solutions to my problem.

I had already subclassed QwtPlotCurve in my application and by using 2)
I was able modify the bounding rectangle and remove Inf from it. (I
replaced inf with something very close to DOUBLE_MAX).

This solved my crash problem!
Tank you for your help

Best regards
Peter Nordin
Post by Uwe Rathmann
Post by Peter Nordin
I am not sure what should really happen when you try to plot something
that is inf, but it would be nice if the scale could handle it without
crashing somehow.
Well I could add some checks here and there, but without adding sanity
checks for every sample it won't help much.
But these type of checks slow down replotting - something I don't want
to do, considering that we are talking about issues that should be
handled/fixed on application side anyway.
Uwe
------------------------------------------------------------------------------
Start Your Social Network Today - Download eXo Platform
Build your Enterprise Intranet with eXo Platform Software
Java Based Open Source Intranet - Social, Extensible, Cloud Ready
Get Started Now And Turn Your Intranet Into A Collaboration Platform
http://p.sf.net/sfu/ExoPlatform
_______________________________________________
qwt-interest mailing list
https://lists.sourceforge.net/lists/listinfo/qwt-interest
Loading...