Skip to content

Commit

Permalink
Eliminate complex typed static variables
Browse files Browse the repository at this point in the history
Complex typed static variables (e.g. maps) in dll-s are to avoid.
On Windows they are not initialised in time (or at all) when the dll
is dynamically loaded. The current use of static QHash data members
results in crash on Windows when the PythonQt.dll is loaded.

See details here:
http://stackoverflow.com/questions/5114683/loading-dll-not-initializing-static-c-classes
  • Loading branch information
espakm committed Feb 10, 2016
1 parent 503597b commit 127d894
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 153 deletions.
2 changes: 0 additions & 2 deletions src/PythonQtClassInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@
#include <QMetaObject>
#include <QMetaEnum>

QHash<QByteArray, int> PythonQtMethodInfo::_parameterTypeDict;

PythonQtClassInfo::PythonQtClassInfo() {
_meta = NULL;
_constructors = NULL;
Expand Down
14 changes: 7 additions & 7 deletions src/PythonQtClassWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper)
{
PyObject* result = NULL;
static QByteArray memberName = "__invert__";
static const char* memberName = "__invert__";
PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
if (opSlot._type == PythonQtMemberInfo::Slot) {
result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
Expand All @@ -63,7 +63,7 @@ static PyObject* PythonQtInstanceWrapper_invert(PythonQtInstanceWrapper* wrapper
static PyObject* PythonQtInstanceWrapper_negative(PythonQtInstanceWrapper* wrapper)
{
PyObject* result = NULL;
static QByteArray memberName = "__sub__";
static const char* memberName = "__sub__";
PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
if (opSlot._type == PythonQtMemberInfo::Slot) {
result = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
Expand All @@ -75,7 +75,7 @@ static int PythonQtInstanceWrapper_nonzero(PythonQtInstanceWrapper* wrapper)
{
int result = (wrapper->_wrappedPtr == NULL && wrapper->_obj == NULL)?0:1;
if (result) {
static QByteArray memberName = "__nonzero__";
static const char* memberName = "__nonzero__";
PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
if (opSlot._type == PythonQtMemberInfo::Slot) {
PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
Expand All @@ -92,7 +92,7 @@ static Py_ssize_t PythonQtInstanceWrapper_length(PythonQtInstanceWrapper* wrappe
{
qint64 result = -1;
if (wrapper->_wrappedPtr != NULL || wrapper->_obj != NULL) {
static QByteArray memberName = "__len__";
static const char* memberName = "__len__";
PythonQtMemberInfo opSlot = wrapper->classInfo()->member(memberName);
if (opSlot._type == PythonQtMemberInfo::Slot) {
PyObject* resultObj = PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, opSlot._slot, NULL, NULL, wrapper->_wrappedPtr);
Expand Down Expand Up @@ -191,15 +191,15 @@ static PyObject* PythonQtInstanceWrapper_mul(PyObject* self, PyObject* other)
#define BINARY_OP(NAME) \
static PyObject* PythonQtInstanceWrapper_ ## NAME(PyObject* self, PyObject* other) \
{ \
static const QByteArray opName("__" #NAME "__"); \
static const const char* opName("__" #NAME "__"); \
return PythonQtInstanceWrapper_binaryfunc(self, other, opName); \
}

#define BINARY_OP_INPLACE(NAME) \
static PyObject* PythonQtInstanceWrapper_i ## NAME(PyObject* self, PyObject* other) \
{ \
static const QByteArray opName("__i" #NAME "__"); \
static const QByteArray fallbackName("__" #NAME "__"); \
static const const char* opName("__i" #NAME "__"); \
static const const char* fallbackName("__" #NAME "__"); \
return PythonQtInstanceWrapper_binaryfunc(self, other, opName, fallbackName); \
}

Expand Down
43 changes: 28 additions & 15 deletions src/PythonQtConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,21 @@ PythonQtValueStorage<qint64, 128> PythonQtConv::global_valueStorage;
PythonQtValueStorage<void*, 128> PythonQtConv::global_ptrStorage;
PythonQtValueStorageWithCleanup<QVariant, 128> PythonQtConv::global_variantStorage;

QHash<int, PythonQtConvertMetaTypeToPythonCB*> PythonQtConv::_metaTypeToPythonConverters;
QHash<int, PythonQtConvertPythonToMetaTypeCB*> PythonQtConv::_pythonToMetaTypeConverters;
QHash<int, PythonQtConvertMetaTypeToPythonCB*>* PythonQtConv::GetMetaTypeToPythonConverters() {
static QHash<int, PythonQtConvertMetaTypeToPythonCB*>* _metaTypeToPythonConverters = nullptr;
if (_metaTypeToPythonConverters == nullptr) {
_metaTypeToPythonConverters = new QHash<int, PythonQtConvertMetaTypeToPythonCB*>();
}
return _metaTypeToPythonConverters;
}

QHash<int, PythonQtConvertPythonToMetaTypeCB*>* PythonQtConv::GetPythonToMetaTypeConverters() {
static QHash<int, PythonQtConvertPythonToMetaTypeCB*>* _pythonToMetaTypeConverters = nullptr;
if (_pythonToMetaTypeConverters == nullptr) {
_pythonToMetaTypeConverters = new QHash<int, PythonQtConvertPythonToMetaTypeCB*>();
}
return _pythonToMetaTypeConverters;
}

PyObject* PythonQtConv::GetPyBool(bool val)
{
Expand Down Expand Up @@ -103,7 +116,7 @@ PyObject* PythonQtConv::ConvertQtValueToPython(const PythonQtMethodInfo::Paramet

if (info.typeId >= QMetaType::User) {
// if a converter is registered, we use is:
PythonQtConvertMetaTypeToPythonCB* converter = _metaTypeToPythonConverters.value(info.typeId);
PythonQtConvertMetaTypeToPythonCB* converter = GetMetaTypeToPythonConverters()->value(info.typeId);
if (converter) {
return (*converter)(info.pointerCount==0?data:*((void**)data), info.typeId);
}
Expand Down Expand Up @@ -254,7 +267,7 @@ PyObject* PythonQtConv::convertQtValueToPythonInternal(int type, const void* dat
default:
// check if we have a QList of pointers, which we can circumvent with a QList<void*>
if (info.isQList && (info.innerNamePointerCount == 1)) {
static int id = QMetaType::type("QList<void*>");
int id = QMetaType::type("QList<void*>");
PythonQtValueStorage_ADD_VALUE(global_variantStorage, QVariant, QVariant::Type(id), ptr);
// return the constData pointer that will be filled with the result value later on
ptr = (void*)((QVariant*)ptr)->constData();
Expand Down Expand Up @@ -295,13 +308,13 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo
{
void* ptr = alreadyAllocatedCPPObject;

static int penId = QMetaType::type("QPen");
static int brushId = QMetaType::type("QBrush");
static int cursorId = QMetaType::type("QCursor");
static int colorId = QMetaType::type("QColor");
static PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
int penId = QMetaType::type("QPen");
int brushId = QMetaType::type("QBrush");
int cursorId = QMetaType::type("QCursor");
int colorId = QMetaType::type("QColor");
PyObject* qtGlobalColorEnum = PythonQtClassInfo::findEnumWrapper("Qt::GlobalColor", NULL);
if (typeId == cursorId) {
static PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
PyObject* qtCursorShapeEnum = PythonQtClassInfo::findEnumWrapper("Qt::CursorShape", NULL);
if ((PyObject*)obj->ob_type == qtCursorShapeEnum) {
Qt::CursorShape val = (Qt::CursorShape)PyInt_AsLong(obj);
if (!ptr) {
Expand All @@ -313,7 +326,7 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo
}
} else if (typeId == penId) {
// brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AsLong(obj);
if (!ptr) {
Expand All @@ -332,7 +345,7 @@ void* PythonQtConv::handlePythonToQtAutoConversion(int typeId, PyObject* obj, vo
}
} else if (typeId == brushId) {
// brushes can be created from QColor and from Qt::GlobalColor (and from brushes, but that's the default)
static PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
PyObject* qtColorClass = PythonQt::priv()->getClassInfo("QColor")->pythonQtClassWrapper();
if ((PyObject*)obj->ob_type == qtGlobalColorEnum) {
Qt::GlobalColor val = (Qt::GlobalColor)PyInt_AsLong(obj);
if (!ptr) {
Expand Down Expand Up @@ -649,7 +662,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i
if (info.typeId == PythonQtMethodInfo::Unknown || info.typeId >= QMetaType::User) {
// check for QList<AnyPtr*> case, where we will use a QList<void*> QVariant
if (info.isQList && (info.innerNamePointerCount == 1)) {
static int id = QMetaType::type("QList<void*>");
int id = QMetaType::type("QList<void*>");
if (!alreadyAllocatedCPPObject) {
PythonQtValueStorage_ADD_VALUE_IF_NEEDED(alreadyAllocatedCPPObject, global_variantStorage, QVariant, QVariant::Type(id), ptr);
ptr = (void*)((QVariant*)ptr)->constData();
Expand All @@ -668,7 +681,7 @@ void* PythonQtConv::ConvertPythonToQt(const PythonQtMethodInfo::ParameterInfo& i
// We only do this for registered type > QMetaType::User for performance reasons.
if (info.typeId >= QMetaType::User) {
// Maybe we have a special converter that is registered for that type:
PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(info.typeId);
PythonQtConvertPythonToMetaTypeCB* converter = GetPythonToMetaTypeConverters()->value(info.typeId);
if (converter) {
if (!alreadyAllocatedCPPObject) {
// create a new empty variant of concrete type:
Expand Down Expand Up @@ -1174,7 +1187,7 @@ QVariant PythonQtConv::PyObjToQVariant(PyObject* val, int type)
} else if (type >= QVariant::UserType) {
// not an instance wrapper, but there might be other converters
// Maybe we have a special converter that is registered for that type:
PythonQtConvertPythonToMetaTypeCB* converter = _pythonToMetaTypeConverters.value(type);
PythonQtConvertPythonToMetaTypeCB* converter = GetPythonToMetaTypeConverters()->value(type);
if (converter) {
// allocate a default object of the needed type:
v = QVariant(type, (const void*)NULL);
Expand Down
8 changes: 4 additions & 4 deletions src/PythonQtConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,10 @@ class PYTHONQT_EXPORT PythonQtConv {
static QString CPPObjectToString(int type, const void* data);

//! register a converter callback from python to cpp for given metatype
static void registerPythonToMetaTypeConverter(int metaTypeId, PythonQtConvertPythonToMetaTypeCB* cb) { _pythonToMetaTypeConverters.insert(metaTypeId, cb); }
static void registerPythonToMetaTypeConverter(int metaTypeId, PythonQtConvertPythonToMetaTypeCB* cb) { GetPythonToMetaTypeConverters()->insert(metaTypeId, cb); }

//! register a converter callback from cpp to python for given metatype
static void registerMetaTypeToPythonConverter(int metaTypeId, PythonQtConvertMetaTypeToPythonCB* cb) { _metaTypeToPythonConverters.insert(metaTypeId, cb); }
static void registerMetaTypeToPythonConverter(int metaTypeId, PythonQtConvertMetaTypeToPythonCB* cb) { GetMetaTypeToPythonConverters()->insert(metaTypeId, cb); }

//! converts the Qt parameter given in \c data, interpreting it as a \c type registered qvariant/meta type, into a Python object,
static PyObject* convertQtValueToPythonInternal(int type, const void* data);
Expand All @@ -187,8 +187,8 @@ class PYTHONQT_EXPORT PythonQtConv {
static PythonQtValueStorageWithCleanup<QVariant, 128> global_variantStorage;

protected:
static QHash<int, PythonQtConvertMetaTypeToPythonCB*> _metaTypeToPythonConverters;
static QHash<int, PythonQtConvertPythonToMetaTypeCB*> _pythonToMetaTypeConverters;
static QHash<int, PythonQtConvertMetaTypeToPythonCB*>* GetMetaTypeToPythonConverters();
static QHash<int, PythonQtConvertPythonToMetaTypeCB*>* GetPythonToMetaTypeConverters();

//! handle automatic conversion of some special types (QColor, QBrush, ...)
static void* handlePythonToQtAutoConversion(int typeId, PyObject* obj, void* alreadyAllocatedCPPObject);
Expand Down
2 changes: 1 addition & 1 deletion src/PythonQtImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ QString PythonQtImport::replaceExtension(const QString& str, const QString& ext)
PyObject* PythonQtImport::getCodeFromPyc(const QString& file)
{
PyObject* code;
const static QString pycStr("pyc");
const QString pycStr("pyc");
QString pyc = replaceExtension(file, pycStr);
if (PythonQt::importInterface()->exists(pyc)) {
time_t mtime = 0;
Expand Down
22 changes: 11 additions & 11 deletions src/PythonQtInstanceWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,46 +248,46 @@ static PyObject *PythonQtInstanceWrapper_richcompare(PythonQtInstanceWrapper* wr
return Py_NotImplemented;
}

QByteArray memberName;
const char* memberName;
switch (code) {
case Py_LT:
{
static QByteArray name = "__lt__";
static const char* name = "__lt__";
memberName = name;
}
break;

case Py_LE:
{
static QByteArray name = "__le__";
static const char* name = "__le__";
memberName = name;
}
break;

case Py_EQ:
{
static QByteArray name = "__eq__";
static const char* name = "__eq__";
memberName = name;
}
break;

case Py_NE:
{
static QByteArray name = "__ne__";
static const char* name = "__ne__";
memberName = name;
}
break;

case Py_GT:
{
static QByteArray name = "__gt__";
static const char* name = "__gt__";
memberName = name;
}
break;

case Py_GE:
{
static QByteArray name = "__ge__";
static const char* name = "__ge__";
memberName = name;
}
break;
Expand Down Expand Up @@ -405,7 +405,7 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
}

{
static const QByteArray dynamicDictString("py_dynamic_dict");
static const char* dynamicDictString("py_dynamic_dict");
// check for a dynamic dict getter slot
PythonQtMemberInfo member = wrapper->classInfo()->member(dynamicDictString);
if (member._type == PythonQtMemberInfo::Slot) {
Expand Down Expand Up @@ -490,15 +490,15 @@ static PyObject *PythonQtInstanceWrapper_getattro(PyObject *obj,PyObject *name)
break;
case PythonQtMemberInfo::NotFound:
{
static const QByteArray getterString("py_get_");
const QByteArray getterString("py_get_");
// check for a getter slot
PythonQtMemberInfo member = wrapper->classInfo()->member(getterString + attributeName);
if (member._type == PythonQtMemberInfo::Slot) {
return PythonQtSlotFunction_CallImpl(wrapper->classInfo(), wrapper->_obj, member._slot, NULL, NULL, wrapper->_wrappedPtr);
}

{
static const QByteArray dynamicGetterString("py_dynamic_get_attrib");
static const char* dynamicGetterString("py_dynamic_get_attrib");
// check for a dynamic getter slot
PythonQtMemberInfo member = wrapper->classInfo()->member(dynamicGetterString);
if (member._type == PythonQtMemberInfo::Slot) {
Expand Down Expand Up @@ -625,7 +625,7 @@ static int PythonQtInstanceWrapper_setattro(PyObject *obj,PyObject *name,PyObjec
}
else if (member._type == PythonQtMemberInfo::NotFound) {
// check for a setter slot
static const QByteArray setterString("py_set_");
const QByteArray setterString("py_set_");
PythonQtMemberInfo setter = wrapper->classInfo()->member(setterString + attributeName);
if (setter._type == PythonQtMemberInfo::Slot) {
// call the setter and ignore the result value
Expand Down

0 comments on commit 127d894

Please sign in to comment.