Exception during hkRefVariant::set() / hkClass::getName()

Exception during hkRefVariant::set() / hkClass::getName()

Hi.

I am trying to serialize some Havok scene data from a C++ library I call from my C# app. However I get an exception when hkRootLevelContainer::NamedVariant::set() is called. I am linking against the debug_dll of the "Free Havok Physics & Animation" package for PC (Binary-only).

 

My code looks something like this:

void MyClass::SaveMesh()
{
    hkxScene *scene = new hkxScene;

    // Fill scene with hkxNode and hkxMesh
    // ...

    hkRootLevelContainer* currentRootContainer = new hkRootLevelContainer();
    currentRootContainer->m_namedVariants.setSize(1);
    hkRootLevelContainer::NamedVariant& sceneVariant = currentRootContainer->m_namedVariants[0];
    sceneVariant.set("Scene Data", scene, &hkxSceneClass);    // <- exception here
    
    // Serialize currentRootContainer
    // ...
}

 

When I run my app, I get the following exceptions:

First-chance exception at 0x572641da (MyLib.dll) in MyApp.exe: 0xC0000005: Access violation reading location 0x00000000. If there is a handler for this exception, the program may be safely continued.

 

The following is output to the console:

DBGHELP: Symbol Search Path: .
DBGHELP: SymSrv load failure: symsrv.dll
DBGHELP: MyLib - private symbols & lines 
         .\MyLib.pdb
DBGHELP: .\clr.pdb - file not found
DBGHELP: .\dll\clr.pdb - file not found
DBGHELP: .\symbols\dll\clr.pdb - file not found
DBGHELP: clr.pdb - file not found
DBGHELP: clr - export symbols
**************************************************************
* Cannot find symbol for an address
* Either debug information was not found or your version of
* dbghelp.dll may be too old to understand the debug format.
* For more information, see comments in hkStackTracerWin32.cxx
* Y:\NightlyJobs\07-18-Thu-01\Source\Common/Base/System/StackTracer/Impl/hkStackTracerWin32.cxx
**************************************************************
MyApp.exe has triggered a breakpoint

 

Finally, here is the Stack Trace:

MyLib.dll!hkClass::getName()  + 0xa bytes    
MyLib.dll!hkRefVariant::getClass()  + 0x156 bytes    
MyLib.dll!hkRefVariant::set()  + 0x14 bytes    
MyLib.dll!hkRootLevelContainer::NamedVariant::set(const char * name, void * object, const hkClass * klass)  Line 40    C++
MyLib.dll!MyClass::SaveMesh()  Line 229    C++
[External Code]    
MyLib.dll!MyLib::MyClass::SaveMesh() Line 70 + 0x46 bytes    C++
MyApp.exe!MyApp.App.App() Line 57 + 0x14 bytes    C#
[External Code]    
mscoreei.dll!6dc4f4f3()     
[Frames below may be incorrect and/or missing, no symbols loaded for mscoreei.dll]    
mscoree.dll!6dcc7f16()     
mscoree.dll!6dcc4de3()     
kernel32.dll!7559338a()     
ntdll.dll!777e9f72()     
ntdll.dll!777e9f45()    

 

I believe this is just caused by a string that is not correctly initialized. However, I cannot find which one ; all the name fields in the objects I use in my code seem correctly set. Can you see where the problem comes from?

 

 

 

 

 

 

4 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

I noticed that the following code generates the same error:

 

hkVariant unnamedSceneVariant = { scene, &hkxSceneClass};
hkRefVariant testRefVariant = unnamedSceneVariant; // <- exception here

 

Also, I do not understand how it is possible to assign an hkVariant (who does not seem to inheritate from any interface) to an hkRefVariant (who does not seem to define an assignment operator receiving an hkVariant).

 

 

I solved my problem by using the following includes at the top of my .cpp file. Hope this helps someone else:

 

#include <stdio.h>
#include <Common/Base/hkBase.h>
#include <Common/SceneData/Scene/hkxScene.h>
#include <Common/SceneData/Graph/hkxNode.h>
#include <Common/Base/Container/PointerMap/hkPointerMap.h>
#include <Common/Base/Container/String/Deprecated/hkStringOld.h>

#define HK_CLASSES_FILE <Common/Serialize/Classlist/hkClasses.h>
#include <Common/Base/Config/hkProductFeaturesNoPatchesOrCompat.h>
#include <Common/Base/Config/hkProductFeatures.cxx>
#include <Common/Compat/Deprecated/Compat/hkCompat_None.cxx>

// Havok base infrastructure
#include <Common/Base/hkBase.h>
#include <Common/Base/Math/hkMath.h>

// Keycode
#include <Common/Base/keycode.cxx>

#include <Common/Base/Ext/hkBaseExt.h>
#include <Common/Base/System/hkBaseSystem.h>
#include <Common/Base/Memory/System/hkMemorySystem.h>
#include <Common/Base/Memory/System/Util/hkMemoryInitUtil.h>
#include <Common/Base/Memory/Allocator/Malloc/hkMallocAllocator.h>
#include <Common/Base/System/Error/hkError.h>
#include <Common/SceneData/Mesh/hkxMesh.h>

#include <Common/Base/hkBase.h>
#include <Common/Base/Math/hkMath.h>
#include <Common/SceneData/Mesh/hkxMesh.h>
#include <Common/SceneData/Mesh/hkxMeshSection.h>
#include <Common/Serialize/Util/hkSerializeUtil.h>
#include <Common/SceneData/Scene/hkxScene.h>
#include <Common/Serialize/Util/hkRootLevelContainer.h>
#include <Common/Base/System/Io/IStream/hkIStream.h>
#include <Common/Serialize/Resource/hkResource.h>
#include <Common/SceneData/Environment/hkxEnvironment.h>
#include <Common/Serialize/ResourceDatabase/hkResourceHandle.h>
#include <Common/Base/Ext/hkBaseExt.h>
#include <Common/Base/Fwd/hkwindows.h>

 

Hi wip,
Here's what I think on this weird crashes you're getting.

First, you can assign an hkVariant to an hkRefVariant during construction because of the hkRefVariant construction that takes an hkVariant&.
This doesn't have much to do with the exceptions you're getting though.

void MyClass::SaveMesh()
{
    hkxScene *scene = new hkxScene;
    // Fill scene with hkxNode and hkxMesh
    // ...
    hkRootLevelContainer* currentRootContainer = new hkRootLevelContainer();
    currentRootContainer->m_namedVariants.setSize(1);
    hkRootLevelContainer::NamedVariant& sceneVariant = currentRootContainer->m_namedVariants[0];
    sceneVariant.set("Scene Data", scene, &hkxSceneClass);    // <- exception here
    // Serialize currentRootContainer
    // ...
}

The line sceneVariant.set("Scene Data", scene, &hkxSceneClass) will pass the address of the area of memory where hkxSceneClass is supposed to live to the set() method and this will in turn do:

HK_FORCE_INLINE void hkRootLevelContainer::NamedVariant::set(const char* name, void* object, const hkClass* klass)
{
    m_name = name;
    m_variant.set(object, klass);
    m_className = m_variant.getClass() ? m_variant.getClass()->getName() : HK_NULL;
}

m_variant is going to be initialized with the klass pointer received as an argument:

void hkRefVariant::set(void* o, const hkClass* k)
{
    HK_ON_DEBUG(checkObject(o, k));
    hkRefPtr<hkReferencedObject>::operator=(static_cast<hkReferencedObject*>(o));
}

And m_variant.getClass() works as follows:

const hkClass* hkRefVariant::getClass() const
{
    if( HK_NULL != val() )
    {
        const hkVtableClassRegistry& vtable = hkVtableClassRegistry::getInstance();
        const hkClass* realClass = vtable.getClassFromVirtualInstance(val());
        HK_ON_DEBUG(checkObject(val(), realClass));
        return realClass;
    }
    return HK_NULL;
}

With

template<class TYPE>
HK_FORCE_INLINE TYPE* hkRefPtr<TYPE>::val() const
{
    return m_pntr;
}

So... There's something that doesn't quite make sense in your callstack, specifically the stack:

MyLib.dll!hkClass::getName()  + 0xa bytes    
MyLib.dll!hkRefVariant::getClass()  + 0x156 bytes    
MyLib.dll!hkRefVariant::set()  + 0x14 bytes    
MyLib.dll!hkRootLevelContainer::NamedVariant::set(const char * name, void * object, const hkClass * klass)  Line 40    C++
MyLib.dll!MyClass::SaveMesh()  Line 229    C++

Seems to indicate that hkRefVariant::set() is calling hkRefVariant::getClass() before the crash, which is not true as set() doesn't call getClass(). Since the call stack is corrupted is hard to understand what's going on, but I think that something is corrupting the code section of your program.

The fact that you fixed this simply by including more stuff is even more suspicious as it indicates that probably you just worked around this specific issue but something is probably still thrashing the memory and sooner or later you'll run into more weird crashes.

Debugging this is going to be tricky, I'd suggest starting from a case that reproduces this reliably and working your way from the beginning of the execution and see where things are going wrong.

Good luck!

Cheers,
Daniele

Try not to become a man of success, but rather try to become a man of value.

Leave a Comment

Please sign in to add a comment. Not a member? Join today