MSVC 2013 BUG, проблемы c выравниванием
От: nen777w  
Дата: 17.02.16 10:55
Оценка:
Вот такой вот презабавный 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.

Насколько я пока понимаю, здесь явно какая то проблема с выравниванием.
Пока буду разбираться дальше, опубликую позже ещё более минимальную верисю примера.
Интересно что думаете?
Отредактировано 17.02.2016 11:19 nen777w . Предыдущая версия . Еще …
Отредактировано 17.02.2016 10:59 nen777w . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.