Вот такой вот презабавный BUG обнаружился.
| | "Много кода." |
| | #include <iostream>
#include <vector>
#define GEN_CTOR(class_name)
/*
public: \
class_name() \
{ \
std::cout << #class_name << std::endl; \
}
*/
class Object;
class ObjectHolder
{
protected:
Object* m_obj;
ObjectHolder(Object* p = NULL) : m_obj(p)
{
}
friend class Object;
virtual void reset_internal() = 0;
public:
~ObjectHolder()
{}
};
template<class PointeeT>
class SharedPtr : public ObjectHolder
{
public:
SharedPtr() : m_pointee(0)
{
}
private:
PointeeT* m_pointee;
virtual void reset_internal()
{
m_pointee = 0;
}
};
template<typename T> class Array;
template<typename T>
class ArrayPtr : public SharedPtr < Array<T> >
{
public:
ArrayPtr() {}
};
template<typename T>
class Array {};
class Object
{
public:
Object()
{
std::cout << "Object" << std::endl;
}
virtual ~Object() {}
virtual void Equals() {}
virtual void GetHashCode() const {}
virtual void ToString() const {}
virtual void MemberwiseClone() const {}
virtual void GetType() const {}
virtual void Is() const {}
virtual void GetSharedMembers() {}
private:
int m_instanceNo;
int* volatile m_objectMutex;
int volatile m_nSharedRefs;
int* m_weakPtrCounter;
//char sz[20];
};
class ISetableInformation : public virtual Object
{
GEN_CTOR(ISetableInformation)
};
class IPdfPrimitive : public virtual Object
{
GEN_CTOR(IPdfPrimitive)
public:
virtual void get_Parent() = 0;
virtual void set_Parent() = 0;
virtual void get_Bytes() = 0;
virtual void get_VersionOfAppearence() = 0;
virtual void get_IsStream() = 0;
virtual void get_IsName() = 0;
virtual void get_IsDictionary() = 0;
virtual void get_IsArray() = 0;
virtual void get_IsPdfString() = 0;
virtual void get_IsNull() = 0;
virtual void get_IsObject() = 0;
virtual void get_IsComment() = 0;
virtual void get_IsBoolean() = 0;
virtual void get_IsNumber() = 0;
virtual void get_PdfPrimitiveType() = 0;
virtual void ToStream() = 0;
virtual void ToPdfString() = 0;
virtual void ToName() = 0;
virtual void ToDictionary() = 0;
virtual void ToArray() = 0;
virtual void ToNull() = 0;
virtual void ToBoolean() = 0;
virtual void ToObject() = 0;
virtual void ToComment() = 0;
virtual void ToNumber() = 0;
virtual void Copy() = 0;
virtual void CreateSerializer() = 0;
virtual void ToString() = 0;
};
class ITrailable : public virtual Object
{
GEN_CTOR(ITrailable)
public:
virtual void get_Original() = 0;
virtual void get_Registrar() = 0;
virtual void get_Password() = 0;
virtual void get_Encryptor() = 0;
virtual void get_EncryptDictionary() = 0;
virtual void get_Context() = 0;
};
class IPdfObject : public virtual IPdfPrimitive, public virtual ITrailable
{
GEN_CTOR(IPdfObject)
public:
virtual void get_Primitive() = 0;
virtual void get_IsModified() = 0;
virtual void set_IsModified() = 0;
virtual void get_Reference() = 0;
virtual void get_ObjectID() = 0;
virtual void get_Generation() = 0;
virtual void get_Value() = 0;
virtual void set_Value() = 0;
};
class IPdfFunction : public virtual IPdfObject
{
GEN_CTOR(IPdfFunction)
public:
virtual void get_FunctionType() = 0;
virtual void get_Domain() = 0;
virtual void get_Range() = 0;
virtual void get_InputCount() = 0;
virtual void get_OutputCount() = 0;
virtual void Eval() = 0;
};
class ISerializeble : public virtual Object
{
GEN_CTOR(ISerializeble)
public:
virtual void get_PrimitiveType() = 0;
virtual void get_ContentsParsingMode() = 0;
virtual void set_ContentsParsingMode() = 0;
virtual void CreateSerializer() = 0;
virtual void CanRead() = 0;
virtual void CanRead(int) = 0;
virtual void CanWrite() = 0;
virtual void TryDeserialize() = 0;
};
class PdfPrimitive : public virtual IPdfPrimitive, public virtual ITrailable, public virtual ISerializeble
{
public:
PdfPrimitive()
{
std::cout << "PdfPrimitive" << std::endl;
}
public:
virtual void get_Original() {}
virtual void set_Original() {}
virtual void get_Registrar() {}
virtual void get_Password() {}
virtual void get_Encryptor() {}
virtual void get_EncryptDictionary() {}
virtual void get_Context() {}
virtual void get_Parent() {}
virtual void set_Parent() {}
void get_Bytes() {}
void get_IsStream() {}
void get_IsName() {}
void get_IsDictionary() {}
void get_IsArray() {}
void get_IsPdfString() {}
void get_IsNull() {}
void get_IsObject() {}
void get_IsComment() {}
void get_IsBoolean() {}
void get_IsNumber() {}
virtual void get_VersionOfAppearence() {}
virtual void get_PdfPrimitiveType() = 0;
virtual void get_ContentsParsingMode() {}
virtual void set_ContentsParsingMode() {}
virtual void get_PrimitiveType() {}
virtual void TryDeserialize() {}
virtual void ToStream() {}
virtual void ToPdfString() {}
virtual void ToName() {}
virtual void ToDictionary() {}
virtual void ToArray() {}
virtual void ToNull() {}
virtual void ToBoolean() {}
virtual void ToObject() {}
virtual void ToComment() {}
virtual void ToNumber() {}
virtual void Copy() {}
virtual void CreateSerializer() = 0;
virtual void ToString() {}
virtual void CanRead() {}
virtual void CanRead(int) {}
virtual void CanWrite() {}
protected:
virtual void CreateInstance() = 0;
void GetSharedMembers() override {}
private:
SharedPtr<IPdfObject> _parent;
SharedPtr<ITrailable> _trailerable;
bool _contentsParsingMode;
bool _loading;
};
class PdfObject : public PdfPrimitive, public virtual ISerializeble, public virtual IPdfObject, public ISetableInformation
{
public:
PdfObject(int)
{
}
PdfObject(int v, int)
: PdfObject(v)
{
std::cout << "PdfObject" << std::endl;
}
public:
virtual void get_PdfPrimitiveType() {}
void get_Value() {}
void set_Value() {}
virtual void get_Parent() {}
virtual void set_Parent() {}
void get_Primitive() {}
void get_IsModified() {}
void set_IsModified() {}
void get_Reference() {}
void get_ObjectID() {}
void get_Generation() {}
virtual void get_ContentsParsingMode() {}
virtual void set_ContentsParsingMode() {}
virtual void Copy() {}
virtual void ToStream() {}
virtual void ToPdfString() {}
virtual void ToName() {}
virtual void ToDictionary() {}
virtual void ToArray() {}
virtual void ToNull() {}
virtual void ToBoolean() {}
virtual void ToObject() {}
virtual void ToComment() {}
virtual void ToNumber() {}
virtual void ToString() {}
virtual void Equals() {}
virtual void GetHashCode() {}
virtual void CreateSerializer() {}
virtual void TryDeserialize() {}
protected:
virtual void CreateInstance() {}
private:
void CanRead(int) {}
void CanRead() {}
void CanWrite() {}
int _generation;
int _objectId;
SharedPtr<IPdfPrimitive> _value;
};
class PdfFunction : public IPdfFunction, public PdfObject
{
public:
PdfFunction(int v)
: PdfObject(v, 10)
{
std::cout << "PdfFunction" << std::endl;
}
public:
virtual void get_FunctionType() = 0;
void get_Domain() {}
void get_Range() {}
void get_InputCount() {}
void get_OutputCount() {}
virtual void Eval() = 0;
};
class SampleFunction : public PdfFunction
{
public:
SampleFunction(int v)
: PdfFunction(v)
{
std::cout << "SampleFunction" << std::endl;
}
virtual void get_FunctionType() {}
virtual void Eval() {}
ArrayPtr<double> dec;
};
int main(int argc, char* argv[])
{
SampleFunction *f = new SampleFunction(10);
return 0;
}
|
| | |
Сори что кода много, нет времени сейчас делать из этого еще более минимальный пример.
Но суть вот в чём.
Перед началом конструирования членов SampleFunction можно обнаружить что адреса члена ObjectHolder::m_obj равен адресу VTBL в PdfFunction::PdfObject::Object
Это приведёт к тому что когда начнёт выполнться базовый констурктор у dec т.е.
ObjectHolder(Object* p = NULL) : m_obj(p)
это затрёт адрес VTBL. Что приводило к дальнейшим падениям.
Если же изменить наследование у
class PdfFunction : public IPdfFunction, public PdfObject
на
class PdfFunction : public PdfObject, public IPdfFunction
то это приведёт к AV на этапе инициализации таблицы виртуальных функций у PdfFunction.
Насколько я пока понимаю, здесь явно какая то проблема с выравниванием.
Пока буду разбираться дальше, опубликую позже ещё более минимальную верисю примера.
Интересно что думаете?