|
From: Ruth Ivimey-C. <Rut...@iv...> - 2009-07-19 21:21:28
|
Folks,
I'm hoping you can help. I'm writing a Qt4 program that uses the qt
plugin interface to implement loadable "instruments" reflecting
different hardware options. I use the Qt plugin interface to list,
create and delete instruments implemented by each plugin file.
The plugin creates the instrument fine, and the main program gets back
the pointer that "new" returned (as can be seen below in the
non-valgrind text: "New DTP" is in the plugin, "Created instrument" is
in the main program. The main program then deletes the instrument
"Deleting instrument"(by calling into the plugin again) and you can see
that the address remains the same "Delete DTP". I am at a loss as to why
valgrind (and the MS heap code) has "forgotten" this address ... it now
thinks (see line 1/2 way down log) that the original block address,
displayed here as 0x52990a0, was 0x5299090!
This log is from amd64/Fedora 10/valgrind 3.4.1. I've also tried this
code on 32-bit WinXP and on 64-bit Vista, they all fail, so something
bad is happening, but what? I tried a valgrind with a MC_MALLOC_REDZONE
size of 64 bytes to see if that changed anything, but it didn't show
anything different.
After the valgrind log entry I have appended code snippets: more on request.
New DTP @ 0x52990a0
Created instrument @ 0x52990a0 plugin @ 0xb398420
Deleting instrument @ 0x52990a0 plugin @ 0xb398420
Delete DTP @ 0x52990a0
==23127==
==23127== Invalid free() / delete / delete[]
==23127== at 0x4A05E4D: operator delete(void*)
(vg_replace_malloc.c:342)
==23127== by 0xB44772E:
PluginDTP41::deleteInstrument(InstrumentInterface*) (gl_dtp41.cpp:33)
==23127== by 0x43D674: SelectDevice::updateDeviceOptions()
(selectdevice.cpp:70)
==23127== by 0x443CFC: SelectDevice::qt_metacall(QMetaObject::Call,
int, void**) (moc_selectdevice.cpp:71)
==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
void**) (in /usr/lib64/libQtCore.so.4.5.1)
==23127== by 0x3F4B14A440: QComboBox::currentIndexChanged(int) (in
/usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14CAAB: (within /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14E0D0: (within /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14E21C: QComboBox::setCurrentIndex(int) (in
/usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B15300A: QComboBox::qt_metacall(QMetaObject::Call,
int, void**) (in /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
void**) (in /usr/lib64/libQtCore.so.4.5.1)
==23127== by 0x3F3D58FE13:
QAbstractItemModel::rowsInserted(QModelIndex const&, int, int) (in
/usr/lib64/libQtCore.so.4.5.1)
==23127== Address 0x52990a0 is 16 bytes inside a block of size 96
alloc'd
==23127== at 0x4A0700C: operator new(unsigned long)
(vg_replace_malloc.c:230)
==23127== by 0xB4473A4: PluginDTP41::createInstrument(QString,
TargetDefBase const*) const (gl_dtp41.cpp:25)
==23127== by 0x43CA8C: SelectDevice::CreateNewInstrument()
(selectdevice.cpp:43)
==23127== by 0x43D29F: SelectDevice::updateDeviceOptions()
(selectdevice.cpp:62)
==23127== by 0x443CFC: SelectDevice::qt_metacall(QMetaObject::Call,
int, void**) (moc_selectdevice.cpp:71)
==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
void**) (in /usr/lib64/libQtCore.so.4.5.1)
==23127== by 0x3F4B14A440: QComboBox::currentIndexChanged(int) (in
/usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14CAAB: (within /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14E0D0: (within /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B14E21C: QComboBox::setCurrentIndex(int) (in
/usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F4B15300A: QComboBox::qt_metacall(QMetaObject::Call,
int, void**) (in /usr/lib64/libQtGui.so.4.5.1)
==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
void**) (in /usr/lib64/libQtCore.so.4.5.1)
Code in the main program that is calling createInstrument and
deleteInstrument:
------------------------------------------------------
void SelectDevice::updateDeviceOptions(void)
{
if (instrument)
{
currentPlugin->deleteInstrument(instrument);
qDebug() << "Deleting instrument @" << instrument << " plugin @"
<< currentPlugin;
instrument = NULL;
}
m_ui->cbPort->clear();
knownPortTypes.clear();
// create an instrument so as to fetch the valid port types for it...
instrument = CreateNewInstrument();
qDebug() << "Created instrument @" << instrument << " plugin @" <<
currentPlugin;
if (instrument)
{
knownPortTypes = instrument->possiblePorts();
qDebug() << "Deleting instrument @" << instrument << " plugin @"
<< currentPlugin;
currentPlugin->deleteInstrument(instrument);
instrument = NULL;
m_ui->cbPort->addItems(knownPortTypes);
}
}
------------------------------------------------------
Code in the plugin that creates/deletes objects:
------------------------------------------------------
InstrumentInterface *PluginDTP41::createInstrument(QString plugin, const
TargetDefBase *theTarget) const
{
// no need to check "plugin" string at present.
InstrumentInterface *inst = new InstrumentDTP41(theTarget);
qDebug() << "New DTP @" << inst;
return inst;
}
void PluginDTP41::deleteInstrument(InstrumentInterface *inst)
{
qDebug() << "Delete DTP @" << inst;
delete inst;
}
------------------------------------------------------
Finally code in the plugin that is called in the middle:
------------------------------------------------------
InstrumentDTP41::InstrumentDTP41(const TargetDefBase *theTarget)
: InstrumentBase(theTarget)
{
instrumentName = "DTP-41";
srand( (unsigned)time( NULL ) );
}
InstrumentDTP41::~InstrumentDTP41(void)
{
}
QStringList InstrumentDTP41::possiblePorts() const
{
QStringList ports;
ports << "COM1" << "COM2" << "COM3" << "COM4";
return ports;
}
--
Engineer, Author and Webweaver
|
|
From: Ruth Ivimey-C. <Rut...@iv...> - 2009-07-19 22:14:04
|
On Sunday 19 July 2009, Christoph Bartoschek wrote:
> Hi,
>
> could you please show the class InstrumentDTP41? Is multiple interitance
> involved?
Yes, but not straight away and the "multiple" is a pure-virtual.
This is the class that forms the Qt plugin interface. It's multiply inheriting, but this one appears to work ok.
-----------------------------------------
class GL_DTP41_EXPORT PluginDTP41: public QObject, public PluginInterface
{
Q_OBJECT;
Q_INTERFACES(PluginInterface);
public:
PluginDTP41();
virtual ~PluginDTP41();
virtual QStringList plugins() const;
virtual InstrumentInterface *createInstrument(QString plugin, const TargetDefBase *theTarget) const;
virtual void deleteInstrument(InstrumentInterface *i);
};
-----------------------------------------
And this is the one you asked about. It inherits singly from InstrumentBase, which is a class implementing the base functionality of InstrumentInterface, which is pure-virtual. However, InstrumentBase needs to be a QObject, so multiply-inherits QObject and the interface.
So:
InstrumentDTP41
: public InstrumentBase
: public QObject, public InstrumentInterface
-----------------------------------------
class InstrumentDTP41: public InstrumentBase
{
Q_OBJECT;
public:
virtual ~InstrumentDTP41();
InstrumentDTP41(const TargetDefBase *theTarget);
virtual bool ReadTarget(QString &colorant);
virtual QStringList possiblePorts() const;
private:
};
-----------------------------------------
Even the definition of InstrumentBase is big, but this is part of it...
-----------------------------------------
class InstrumentBase: public QObject, public InstrumentInterface
{
Q_OBJECT;
protected:
InstrumentReadMode readMode;
QString portType;
QString portParams;
MeasurementTypes measurementType;
IlluminantTypes illuminant;
QString instrumentName;
QString instrumentSerialNo;
QString instrumentVersion;
const TargetDefBase *target;
MeasurementCollection *densities;
public:
typedef QList<InstrumentCommand> InstrumentCommandList;
InstrumentBase(const TargetDefBase *theTarget);
virtual ~InstrumentBase();
virtual QStringList possiblePorts() const = 0;
virtual QString ToXML() const;
virtual ObserverAngles ObserverAngle() const
{
return OBS_NONE;
};
virtual QString InstrumentName() const
{
return instrumentName;
};
...
virtual void setPortParams(const QString &value)
{
portParams = value;
};
virtual bool Connect() { return true; };
virtual bool Disconnect() { return true; };
private:
Q_DISABLE_COPY(InstrumentBase);
};
-----------------------------------------
> Please also show InstrumentInterface.
It's pure a virtual interface definition:
-----------------------------------------
class InstrumentInterface
{
public:
typedef QList<InstrumentCommand> InstrumentCommandList;
virtual QStringList possiblePorts() const = 0;
virtual QString ToXML() const = 0;
virtual ObserverAngles ObserverAngle() const = 0;
virtual QString InstrumentName() const = 0;
virtual QString InstrumentVersion() const = 0;
virtual QString InstrumentSerialNo() const = 0;
virtual void setInstrumentSerialNo(QString serial) = 0;
virtual const TargetDefBase *Target() const = 0;
virtual void setTarget(TargetDefBase *value) = 0;
virtual MeasurementCollection *Densities() = 0;
virtual InstrumentReadMode ReadMode() const = 0;
virtual IlluminantTypes Illuminant() const = 0;
virtual void setIlluminant(IlluminantTypes value) = 0;
virtual MeasurementTypes MeasurementType() const = 0;
virtual void setMeasurementType(MeasurementTypes value) = 0;
virtual QString PortType() const = 0;
virtual void setPortType(QString value) = 0;
virtual QString PortParams() const = 0;
virtual void setPortParams(const QString &value) = 0;
virtual bool Connect() = 0;
virtual bool Disconnect() = 0;
virtual bool WriteData(QString &dat, int &lenWritten) = 0;
virtual bool ReadData(QString &dat, int numWanted, int &numGot, int timeout) = 0;
virtual bool CheckError() = 0;
virtual bool SendCommand(QString &cmd, SendErrorCheckMode errChk) = 0;
virtual bool SendCommands(InstrumentCommandList &commands, SendErrorCheckMode errChk) = 0;
virtual bool Configure() = 0;
virtual void EndReading() = 0;
virtual bool ReadTarget() = 0;
virtual bool ReadTarget(QString &colorant) = 0;
};
--
Engineer, Author and Webweaver
|
|
From: Christoph B. <bar...@or...> - 2009-07-19 22:23:45
|
Hi,
the following method is missing:
virtual InstrumentInterface::~InstrumentInterface() {}
Include this method and it should work.
Christoph
|
|
From: Christoph B. <bar...@or...> - 2009-07-19 22:15:39
|
Hi,
could you please show the class InstrumentDTP41? Is multiple interitance
involved?
Please also show InstrumentInterface.
Christoph
Am Sonntag, 19. Juli 2009 schrieb Ruth Ivimey-Cook:
> Folks,
>
> I'm hoping you can help. I'm writing a Qt4 program that uses the qt
> plugin interface to implement loadable "instruments" reflecting
> different hardware options. I use the Qt plugin interface to list,
> create and delete instruments implemented by each plugin file.
>
> The plugin creates the instrument fine, and the main program gets back
> the pointer that "new" returned (as can be seen below in the
> non-valgrind text: "New DTP" is in the plugin, "Created instrument" is
> in the main program. The main program then deletes the instrument
> "Deleting instrument"(by calling into the plugin again) and you can see
> that the address remains the same "Delete DTP". I am at a loss as to why
> valgrind (and the MS heap code) has "forgotten" this address ... it now
> thinks (see line 1/2 way down log) that the original block address,
> displayed here as 0x52990a0, was 0x5299090!
>
> This log is from amd64/Fedora 10/valgrind 3.4.1. I've also tried this
> code on 32-bit WinXP and on 64-bit Vista, they all fail, so something
> bad is happening, but what? I tried a valgrind with a MC_MALLOC_REDZONE
> size of 64 bytes to see if that changed anything, but it didn't show
> anything different.
>
> After the valgrind log entry I have appended code snippets: more on
> request.
>
> New DTP @ 0x52990a0
>
> Created instrument @ 0x52990a0 plugin @ 0xb398420
>
> Deleting instrument @ 0x52990a0 plugin @ 0xb398420
>
> Delete DTP @ 0x52990a0
>
> ==23127==
>
> ==23127== Invalid free() / delete / delete[]
>
> ==23127== at 0x4A05E4D: operator delete(void*)
> (vg_replace_malloc.c:342)
> ==23127== by 0xB44772E:
> PluginDTP41::deleteInstrument(InstrumentInterface*) (gl_dtp41.cpp:33)
>
> ==23127== by 0x43D674: SelectDevice::updateDeviceOptions()
> (selectdevice.cpp:70)
> ==23127== by 0x443CFC: SelectDevice::qt_metacall(QMetaObject::Call,
> int, void**) (moc_selectdevice.cpp:71)
> ==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
> void**) (in /usr/lib64/libQtCore.so.4.5.1)
> ==23127== by 0x3F4B14A440: QComboBox::currentIndexChanged(int) (in
> /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B14CAAB: (within /usr/lib64/libQtGui.so.4.5.1)
>
> ==23127== by 0x3F4B14E0D0: (within /usr/lib64/libQtGui.so.4.5.1)
>
> ==23127== by 0x3F4B14E21C: QComboBox::setCurrentIndex(int) (in
> /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B15300A: QComboBox::qt_metacall(QMetaObject::Call,
> int, void**) (in /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
> void**) (in /usr/lib64/libQtCore.so.4.5.1)
> ==23127== by 0x3F3D58FE13:
> QAbstractItemModel::rowsInserted(QModelIndex const&, int, int) (in
> /usr/lib64/libQtCore.so.4.5.1)
>
> ==23127== Address 0x52990a0 is 16 bytes inside a block of size 96
> alloc'd
> ==23127== at 0x4A0700C: operator new(unsigned long)
> (vg_replace_malloc.c:230)
> ==23127== by 0xB4473A4: PluginDTP41::createInstrument(QString,
> TargetDefBase const*) const (gl_dtp41.cpp:25)
> ==23127== by 0x43CA8C: SelectDevice::CreateNewInstrument()
> (selectdevice.cpp:43)
> ==23127== by 0x43D29F: SelectDevice::updateDeviceOptions()
> (selectdevice.cpp:62)
> ==23127== by 0x443CFC: SelectDevice::qt_metacall(QMetaObject::Call,
> int, void**) (moc_selectdevice.cpp:71)
> ==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
> void**) (in /usr/lib64/libQtCore.so.4.5.1)
> ==23127== by 0x3F4B14A440: QComboBox::currentIndexChanged(int) (in
> /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B14CAAB: (within /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B14E0D0: (within /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B14E21C: QComboBox::setCurrentIndex(int) (in
> /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F4B15300A: QComboBox::qt_metacall(QMetaObject::Call,
> int, void**) (in /usr/lib64/libQtGui.so.4.5.1)
> ==23127== by 0x3F3D559421: QMetaObject::activate(QObject*, int, int,
> void**) (in /usr/lib64/libQtCore.so.4.5.1)
>
>
> Code in the main program that is calling createInstrument and
> deleteInstrument:
> ------------------------------------------------------
> void SelectDevice::updateDeviceOptions(void)
> {
> if (instrument)
> {
> currentPlugin->deleteInstrument(instrument);
> qDebug() << "Deleting instrument @" << instrument << " plugin @"
> << currentPlugin;
> instrument = NULL;
> }
>
> m_ui->cbPort->clear();
> knownPortTypes.clear();
>
> // create an instrument so as to fetch the valid port types for it...
> instrument = CreateNewInstrument();
> qDebug() << "Created instrument @" << instrument << " plugin @" <<
> currentPlugin;
> if (instrument)
> {
> knownPortTypes = instrument->possiblePorts();
> qDebug() << "Deleting instrument @" << instrument << " plugin @"
> << currentPlugin;
> currentPlugin->deleteInstrument(instrument);
> instrument = NULL;
> m_ui->cbPort->addItems(knownPortTypes);
> }
> }
> ------------------------------------------------------
>
> Code in the plugin that creates/deletes objects:
> ------------------------------------------------------
> InstrumentInterface *PluginDTP41::createInstrument(QString plugin, const
> TargetDefBase *theTarget) const
> {
> // no need to check "plugin" string at present.
> InstrumentInterface *inst = new InstrumentDTP41(theTarget);
> qDebug() << "New DTP @" << inst;
> return inst;
> }
>
> void PluginDTP41::deleteInstrument(InstrumentInterface *inst)
> {
> qDebug() << "Delete DTP @" << inst;
> delete inst;
> }
> ------------------------------------------------------
>
> Finally code in the plugin that is called in the middle:
> ------------------------------------------------------
> InstrumentDTP41::InstrumentDTP41(const TargetDefBase *theTarget)
>
> : InstrumentBase(theTarget)
>
> {
> instrumentName = "DTP-41";
> srand( (unsigned)time( NULL ) );
> }
>
> InstrumentDTP41::~InstrumentDTP41(void)
> {
> }
>
> QStringList InstrumentDTP41::possiblePorts() const
> {
> QStringList ports;
> ports << "COM1" << "COM2" << "COM3" << "COM4";
> return ports;
> }
|
|
From: Ruth Ivimey-C. <Rut...@iv...> - 2009-07-19 22:32:24
|
On Sunday 19 July 2009, Christoph Bartoschek wrote:
> the following method is missing:
>
> virtual InstrumentInterface::~InstrumentInterface() {}
>
> Include this method and it should work.
Thanks, it did :-) :-)
Can you explain, though, why the symptoms were as seen.. it seems very obscure to me ?
Ruth
--
Engineer, Author and Webweaver
|
|
From: Christoph B. <bar...@or...> - 2009-07-20 06:15:39
|
Am Montag, 20. Juli 2009 schrieb Ruth Ivimey-Cook: > Can you explain, though, why the symptoms were as seen.. it seems very > obscure to me ? http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7 Use the GCC option -Wnon-virtual-dtor. Basically you can imagine that your object consisted by a QObject directly followed by InstrumentInterface. Because you are handling with a pointer to InstrumentInterface your pointer points to an address within the object. InstrumentInterface is 16 bytes after the start of the object. By using the pointer to InstrumentInterface you did not see the real address of your object. Without a virtual destructor the compiler does not know how to access the correct starting point of the object and frees the wrong pointer. Christoph |