tags 474313 patch
thanks

On Sun, Jul 13, 2008 at 07:31:57PM +0200, Georges Khaznadar wrote:
> Hello, I tried to reproduce the bug about a 100 µF capacitor, the way
> you described it:
> 
> > To reproduce, start ktechlab, create a new circuit, drag a capacitor
> > onto it, select the capacitor, then change its value in the top bar.
> 
> and the bug was not triggered. I am using the version 0.3-9 of ktechlab,
> with an amd64 platform.

Strange that it's so different on amd64 - after looking more closely, I was 
able to identify two distinct bugs in the code.

I retried with 0.3-9 inside a sid chroot on my i386 machine. First of all, 
this version *crashed* when I dragged any symbol onto a new circuit. I 
recompiled with debugging symbols and -fno-inline using gcc 4.3.1, and got:

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb5e7b700 (LWP 32442)]
0x082455fd in Map::reset (this=0x8941480) at matrix.cpp:308
308                             (*m_map)[i][j] = 0;
(gdb) bt
#0  0x082455fd in Map::reset (this=0x8941480) at matrix.cpp:308
#1  0x082466ab in Map (this=0x8941480, size=2) at matrix.cpp:292
#2  0x08246776 in Matrix (this=0x893b958, n=2, m=0) at matrix.cpp:35
#3  0x0824220d in ElementSet (this=0x8941920, circuit=0x893ab88, n=2, m=0) at 
elementset.cpp:32
#4  0x0823f77f in Circuit::init (this=0x893ab88) at circuit.cpp:203
...

It turned out that Map::Map() creates a "new ETMap(m_size)" and then calls 
reset(), which assumes that *m_map is square. However, the "new 
ETMap(m_size)" only creates a vector that contains two *empty* vectors, so 
reset() would overwrite random memory. The attached patch fixes this by not 
calling reset() and instead initializing the array properly.
Recommendation to upstream authors: Use valgrind!

OK, this allowed me to actually trigger the bug that I originally reported, 
and which still existed. It turned out to be infinite recursion:

#135 0x0814ec5b in DoubleSpinBox::valueChanged (this=0xa34ccb0, 
t0=9.9999999999999991e-05) at doublespinbox.moc:95
#136 0x0814f63a in DoubleSpinBox::checkIfChanged (this=0xbf7d4aac) at 
doublespinbox.cpp:210
#137 0x0814f7c8 in DoubleSpinBox::qt_invoke (this=0xa34ccb0, _id=56, 
_o=0xbf7d4bdc) at doublespinbox.moc:103
#138 0xb6582f6d in QObject::activate_signal () from /usr/lib/libqt-mt.so.3
#139 0xb65839f0 in QObject::activate_signal () from /usr/lib/libqt-mt.so.3
#140 0xb68c7960 in QSpinBox::valueChanged () from /usr/lib/libqt-mt.so.3
#141 0xb669a4c6 in QSpinBox::valueChange () from /usr/lib/libqt-mt.so.3
#142 0xb668cd59 in QRangeControl::setValue () from /usr/lib/libqt-mt.so.3
#143 0xb6698b23 in QSpinBox::setValue () from /usr/lib/libqt-mt.so.3
#144 0xb669a02b in QSpinBox::interpretText () from /usr/lib/libqt-mt.so.3
#145 0xb6698385 in QSpinBox::value () from /usr/lib/libqt-mt.so.3
#146 0xb6699987 in QSpinBox::currentValueText () from /usr/lib/libqt-mt.so.3
#147 0xb6699bfa in QSpinBox::selectAll () from /usr/lib/libqt-mt.so.3
#148 0xb669a2fb in QSpinBox::updateDisplay () from /usr/lib/libqt-mt.so.3
#149 0xb669a4a8 in QSpinBox::valueChange () from /usr/lib/libqt-mt.so.3
#150 0xb668cd59 in QRangeControl::setValue () from /usr/lib/libqt-mt.so.3
#151 0xb6698b23 in QSpinBox::setValue () from /usr/lib/libqt-mt.so.3
#152 0x0814fb23 in DoubleSpinBox::setValue (this=0xa34ccb0, 
value=9.9999999999999991e-05) at doublespinbox.cpp:78
#153 0x080ca642 in ItemInterface::slotSetData (this=0xa17dad0, [EMAIL 
PROTECTED], value={d = 0xbf7d4fcc}) at iteminterface.cpp:570
#154 0x080cab29 in ItemInterface::tbDataChanged (this=0xa17dad0) at 
iteminterface.cpp:480
#155 0x080cc668 in ItemInterface::qt_invoke (this=0xa17dad0, _id=4, 
_o=0xbf7d50bc) at iteminterface.moc:107
#156 0xb6582f6d in QObject::activate_signal () from /usr/lib/libqt-mt.so.3
#157 0xb658388d in QObject::activate_signal () from /usr/lib/libqt-mt.so.3
#158 0x0814ec5b in DoubleSpinBox::valueChanged (this=0xa34ccb0, 
t0=9.9999999999999991e-05) at doublespinbox.moc:95

The first and last line of the above are the same: The code recurses 
forever updating the widget. This is because in 
DoubleSpinBox::checkIfChanged(), the check "m_lastEmittedValue == newValue" 
never becomes true due to a rounding error.

The bug is that the comparison takes place using a double value (e.g. 
100.0e-6 for 100uF), whereas the widget stores two items, an integer 100 
and a multiplier (like 1.0e-6 for micro). Converting the two back and forth 
never gives an exact match.

(Incidentally, I find it strange that the widget needs to emit "I have 
changed" in response to it receiving a "you have changed". It smells wrong, 
but I don't understand the code well enough to say whether it's a bug.)

My fix is to perform the above comparison on the two values (integer and 
multiplier) rather than the combined double. The patch is attached. I've 
only tested it lightly!

Cheers,

  Richard

-- 
  __   _
  |_) /|  Richard Atterer
  | \/¯|  http://atterer.net
  ¯ '` ¯

--- ./src/gui/doublespinbox.cpp.orig    2008-07-13 20:52:20.247138183 +0000
+++ ./src/gui/doublespinbox.cpp 2008-07-13 21:57:12.163137261 +0000
@@ -33,7 +33,8 @@
 DoubleSpinBox::DoubleSpinBox( double lower, double upper, double minAbs, 
double value, const QString &unit, QWidget * parent )
        : QSpinBox( parent )
 {
-       m_lastEmittedValue = value;
+       m_lastEmittedNumber = 0;
+       m_lastEmittedMult = 0.0;
        m_unit = unit;
        m_minValue = lower;
        m_maxValue = upper;
@@ -201,13 +202,14 @@
 
 void DoubleSpinBox::checkIfChanged()
 {
-       double newValue = value();
-       
-       if ( m_lastEmittedValue == newValue )
+       int num = getDisplayedNumber( 0 );
+       double mult = getMult();
+       if ( m_lastEmittedNumber == num && m_lastEmittedMult ==  mult )
                return;
+       m_lastEmittedNumber = num;
+       m_lastEmittedMult = mult;
        
-       m_lastEmittedValue = newValue;
-       emit valueChanged( m_lastEmittedValue );
+       emit valueChanged( value() );
 }
 
 
--- ./src/gui/doublespinbox.h.orig      2008-07-13 22:20:10.855136297 +0000
+++ ./src/gui/doublespinbox.h   2008-07-13 21:49:19.571137553 +0000
@@ -125,7 +125,8 @@
                double m_minValue;
                double m_maxValue;
                double m_minAbsValue;
-               double m_lastEmittedValue;
+               int m_lastEmittedNumber;
+               double m_lastEmittedMult;
 };
 
 #endif
--- ./src/electronics/simulation/matrix.cpp.orig        2008-07-13 
20:32:07.715136621 +0000
+++ ./src/electronics/simulation/matrix.cpp     2008-07-13 20:44:40.143134992 
+0000
@@ -288,8 +288,15 @@
 Map::Map( const uint size )
 {
        m_size = size;
-       m_map = new ETMap( m_size );
-       reset();
+       m_map = new ETMap(m_size);
+       for ( uint i = 0; i<m_size; i++)
+       {
+               std::vector<uint>* v = &(*m_map)[i];
+               for ( uint j=0; j<m_size; j++ )
+               {
+                       v->push_back(0);
+               }
+       }
 }
 
 



--
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to