Sign in to follow this  

Crash in CallCDeclFunction*/asm __volatile__ on MacOS 32-bit and not in 64-bit

Recommended Posts

simong    242



First of all thank you for this great library! I discovered it a few days ago, and I don't think I'll be able to look back!


I'm having a few issues trying to make it work in 32-bit (i386) with XCode 5 and OSX 10.9. Everything works great in 64-bit and it doesn't seem to change anything to build the library in 32 or 64 bit, a crash always happen in the same file if I try to run the application in 32-bit.


I've found a post on the forum from a few years ago that seams to be related to my problem as everything seems to happen in that same CallCDeclFunctionObjLast, but what I found in the post didn't helped and that bug seems to have been corrected since a few release anyway (that was in 2012!).


If it's relevant, I think that the function the engine is trying to execute is the constructor of an object I registered that way:

   template<typename T, typename P1, typename P2>
       static void constructor(P1 p1, P2 p2, T* ptr) { new (ptr) T(p1,p2); }
r = engine->RegisterObjectBehaviour(name.c_str(),
                                    ( "void f("+type+","+type+")" ).c_str(),
                                    asCALL_CDECL_OBJLAST); assert( r >= 0 );

Actually if I build the library without any debug symbols the only message I got is "error: memory read failed for 0xd04fae00" so that might have something to do with how I handle constructors (which seem to be the way to do it according to the wiki)


So basically I'm a bit lost and wanted to know if that's a known issue, if anyone experienced the same with XCode5/llvm/32bit or if I'm just doing something wrong in my script/binding code.


Any suggestions are welcome!


Thanks a lot!



Edited by simong

Share this post

Link to post
Share on other sites
simong    242

Here's a few more informations;


The crash described above seems to happen at the construction of an object type I registered :

Basic`CallCDeclFunctionObjLast(void const*, unsigned long const*, int, void (*)()) + 153:
0x1d5079:  calll  *12(%ebx)
0x1d507c:  addl   8(%ebx), %esp <------- EXC_BAD_ACCESS HERE
0x1d507f:  addl   $4, %esp
0x1d5082:  popl   %esp
0x1d5083:  popl   %ebx
0x1d5084:  leal   -40(%ebp), %ecx
0x1d5087:  movl   %eax, (%ecx)
0x1d5089:  movl   %edx, 4(%ecx)
0x1d508c:  movl   -40(%ebp), %eax
0x1d508f:  movl   -36(%ebp), %edx
0x1d5092:  movl   (%ebx), %ecx
0x1d5094:  movl   -16(%ebp), %esi
0x1d5097:  cmpl   %esi, %ecx
0x1d5099:  movl   %edx, -60(%ebp)
0x1d509c:  movl   %eax, -64(%ebp)
0x1d509f:  jne    0x1d50b3                  ; CallCDeclFunctionObjLast(void const*, unsigned long const*, int, void (*)()) + 211 at as_callfunc_x86.cpp:460
0x1d50a5:  movl   -64(%ebp), %eax
0x1d50a8:  movl   -60(%ebp), %edx
0x1d50ab:  addl   $60, %esp
0x1d50ae:  popl   %esi
0x1d50af:  popl   %edi
0x1d50b0:  popl   %ebx
0x1d50b1:  popl   %ebp
0x1d50b2:  ret    
0x1d50b3:  calll  0x2b109c                  ; symbol stub for: __stack_chk_fail

Now if I remove all my registration code and only register the stdstring add_on the crash happen in StringFactory/asCThreadReadWriteLock::AcquiredShared(). Here's the disassembly from CallCDeclFunction:

Basic`CallCDeclFunction(unsigned long const*, int, void (*)()) + 137:
0x1d4c09:  calll  *8(%ebx)
0x1d4c0c:  addl   4(%ebx), %esp <------- EXC_BAD_ACCESS HERE
0x1d4c0f:  popl   %esp
0x1d4c10:  popl   %ebx
0x1d4c11:  leal   -32(%ebp), %ecx
0x1d4c14:  movl   %eax, (%ecx)
0x1d4c16:  movl   %edx, 4(%ecx)
0x1d4c19:  movl   -32(%ebp), %eax
0x1d4c1c:  movl   -28(%ebp), %edx
0x1d4c1f:  movl   (%edi), %ecx
0x1d4c21:  movl   -12(%ebp), %esi
0x1d4c24:  cmpl   %esi, %ecx
0x1d4c26:  movl   %edx, -48(%ebp)
0x1d4c29:  movl   %eax, -52(%ebp)
0x1d4c2c:  jne    0x1d4c3f                  ; CallCDeclFunction(unsigned long const*, int, void (*)()) + 191 at as_callfunc_x86.cpp:355
0x1d4c32:  movl   -52(%ebp), %eax
0x1d4c35:  movl   -48(%ebp), %edx
0x1d4c38:  addl   $48, %esp
0x1d4c3b:  popl   %esi
0x1d4c3c:  popl   %edi
0x1d4c3d:  popl   %ebp
0x1d4c3e:  ret    
0x1d4c3f:  calll  0x2b109c                  ; symbol stub for: __stack_chk_fail

Share this post

Link to post
Share on other sites
WitchLord    4677

The fact that the crash happens right after the call to the native function returns indicates that there is a mismatch in the calling convention used by the C++ function and what the assembler code in AngelScript does. 


It could be that Apple changed something in the calling convention they use with Clang.


Can you show me the assembler instructions for the StringFactory? I'm not familiar with the new XCode or Clang, but I'm pretty sure it has an option to allow the compiler to output the assembler code in addition to the normal .obj files. 


Can you also set a break point in the StringFactory and check if the arguments that it receives have appropriate values? 

Share this post

Link to post
Share on other sites
simong    242

Thanks a lot for the quick reply!


Here's the only way I know in xcode to generate assembly code for a specific file. The file is quite big, xcode seems to generate a huge amount of code! I'm going to see if I'm doing it right.


Here's the value for the arguments.... It doesn't look good!

s const char * "\x98\x91*" 0x01c8ff50
*s const char '\x98' '\x98'
length asUINT 3221215084 3221215084

I'm currently running AngelScript 2.28.0 with AS_MAC AS_X86.


Thanks a lot for looking into it, and let me know if there's something else you need!

Edited by simong

Share this post

Link to post
Share on other sites
WitchLord    4677

Something is wrong. The assembler code is for x86-64, not x86-32. 


The very first instruction in the StringFactory is 'pushq %rbp', which means 'push the entire 64bit value from the rbp register onto the stack'. In 32bit mode only the lower 32bits of the registers are accessible, i.e. it ought to do just 'pushd %ebp'. 


Could this be the problem? Are you perhaps compiling the library in 32bit mode, but your application in 64bit mode? One would have thought the linker would give an error if this was the case, but who knows?


Perhaps you just mistakedly generated the assembler code in 64bit mode? Can you check again and generate the 32bit assembler code?

Share this post

Link to post
Share on other sites
simong    242

Indeed sorry about that! Don't know how, but I did accidentally turned back in 64bit when I generated the assembly code.

Here's the updated file:


Unfortunately everything I link in my application is compiled in 32bit, but I'll try to dig a bit more!


Here's the full callstack if it helps :

#0	0x9797b540 in misaligned_stack_error_ ()
#1	0x014815c0 in 0x014815c0 ()
#2	0x002aae37 in asCThreadReadWriteLock::AcquireShared() at angelscript/angelscript/source/as_thread.cpp:409
#3	0x00279158 in asCScriptEngine::GetUserData(unsigned long) const at angelscript/angelscript/source/as_scriptengine.cpp:905
#4	0x000b8244 in StringFactory(unsigned int, char const*) at angelscript/add_on/scriptstdstring/scriptstdstring.cpp:47
#5	0x001d4c0c in CallCDeclFunction(unsigned long const*, int, void (*)()) ()
#6	0x001d47e9 in CallSystemFunctionNative(asCContext*, asCScriptFunction*, void*, unsigned long*, void*, unsigned long long&) at angelscript/angelscript/source/as_callfunc_x86.cpp:158
#7	0x001d3bde in CallSystemFunction(int, asCContext*, void*) at angelscript/angelscript/source/as_callfunc.cpp:487
#8	0x0022bc4d in asCContext::ExecuteNext() at angelscript/angelscript/source/as_context.cpp:2320
#9	0x0022a0ea in asCContext::Execute() at angelscript/angelscript/source/as_context.cpp:1149
#10	0x0009cbbc in as::Script::executeFunction() at src/Script.cpp:153
#11	0x0009cceb in as::Script::call(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) at src/Script.cpp:170
#12	0x00006f0c in BasicApp::setup()::$_0::operator()(std::__1::shared_ptr<cinder::DataSource>) const at src/BasicApp.cpp:49
#13	0x00006b98 in decltype(std::__1::forward<BasicApp::setup()::$_0&>(fp)(std::__1::forward<std::__1::shared_ptr<cinder::DataSource> >(fp0))) std::__1::__invoke<BasicApp::setup()::$_0&, std::__1::shared_ptr<cinder::DataSource> >(BasicApp::setup()::$_0&&&, std::__1::shared_ptr<cinder::DataSource>&&) [inlined] at /Applications/
#14	0x00006b4b in std::__1::__function::__func<BasicApp::setup()::$_0, std::__1::allocator<BasicApp::setup()::$_0>, void (std::__1::shared_ptr<cinder::DataSource>)>::operator()(std::__1::shared_ptr<cinder::DataSource>&&) at /Applications/
#15	0x00082220 in std::__1::function<void (std::__1::shared_ptr<cinder::DataSource>)>::operator()(std::__1::shared_ptr<cinder::DataSource>) const at /Applications/
#16	0x0008109e in AssetManager::Loader::notify() at /Frameworks/Cinder/cinder_master/blocks/Cinder-AngelScript/samples/Basic/blocks/AssetManager/src/AssetManager.cpp:24
#17	0x00081760 in AssetManager::load(boost::filesystem::path const&, std::__1::function<void (std::__1::shared_ptr<cinder::DataSource>)>, AssetManager::Options const&) at /Frameworks/Cinder/cinder_master/blocks/Cinder-AngelScript/samples/Basic/blocks/AssetManager/src/AssetManager.cpp:41
#18	0x00003783 in BasicApp::setup() at /Frameworks/Cinder/cinder_master/blocks/Cinder-AngelScript/samples/Basic/src/BasicApp.cpp:44
#19	0x000d1685 in cinder::app::App::privateSetup__() at /Frameworks/Cinder/cinder_master/src/cinder/app/App.cpp:132
#20	0x000d3782 in -[AppImplCocoaBasic applicationDidFinishLaunching:] at /Frameworks/Cinder/cinder_master/src/cinder/app/
#21	0x90c6d692 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke ()
#23	0x98ae93fb in _CFXNotificationPost ()
#24	0x90c5bebf in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#25	0x97edd7d5 in -[NSApplication _postDidFinishNotification] ()
#26	0x97edd475 in -[NSApplication _sendFinishLaunchingNotification] ()
#27	0x97ed9da4 in -[NSApplication(NSAppleEventHandling) _handleAEOpenEvent:] ()
#28	0x97ed9691 in -[NSApplication(NSAppleEventHandling) _handleCoreEvent:withReplyEvent:] ()
#29	0x97407304 in -[NSObject performSelector:withObject:withObject:] ()
#30	0x90c7c3fa in __76-[NSAppleEventManager setEventHandler:andSelector:forEventClass:andEventID:]_block_invoke ()
#31	0x90c7bf31 in -[NSAppleEventManager dispatchRawAppleEvent:withRawReply:handlerRefCon:] ()
#32	0x90c7bd3b in _NSAppleEventManagerGenericHandler ()
#33	0x925c2b15 in aeDispatchAppleEvent(AEDesc const*, AEDesc*, unsigned long, unsigned char*) ()
#34	0x92591ed6 in dispatchEventAndSendReply(AEDesc const*, AEDesc*) ()
#35	0x92591dce in aeProcessAppleEvent ()
#36	0x990707c1 in AEProcessAppleEvent ()
#37	0x97ed53a8 in _DPSNextEvent ()
#38	0x97ed4ad0 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#39	0x97ec735c in -[NSApplication run] ()
#40	0x000e5e63 in cinder::app::AppBasic::launch(char const*, int, char* const*) at /Frameworks/Cinder/cinder_master/src/cinder/app/AppBasic.cpp:128
#41	0x000d2d16 in cinder::app::App::executeLaunch(cinder::app::App*, std::__1::shared_ptr<cinder::app::Renderer>, char const*, int, char* const*) at /Frameworks/Cinder/cinder_master/src/cinder/app/App.cpp:553
#42	0x0006e272 in cinder::app::AppBasic::executeLaunch(cinder::app::AppBasic*, std::__1::shared_ptr<cinder::app::Renderer>, char const*, int, char* const*) at /Frameworks/Cinder/cinder_master/blocks/Cinder-AngelScript/samples/Basic/xcode/../../../../../include/cinder/app/AppBasic.h:178
#43	0x0000517a in main at /Frameworks/Cinder/cinder_master/blocks/Cinder-AngelScript/samples/Basic/src/BasicApp.cpp:82
#44	0x00002ee5 in start ()

As you can see it breaks after asCThreadReadWriteLock::AcquiredShared(). 

Edited by simong

Share this post

Link to post
Share on other sites
WitchLord    4677

I don't see anything unexpected from the assembler code. The ABI appears to be the same as always.


Can you provide the assembler code for as_callfunc_x86.cpp? I suspect the problem may be that the compiler is doing some odd optimization to the inline assembler code that is breaking the ABI compatibility.


The misaligned_stack_error_ is likely because the stack is no longer aligned to 16bytes which it must be according to the ABI specifications. The inline assembler code in as_callfunc_x86.cpp has code to guarantee this alignment, but if the compiler is indeed doing some odd optimization on it it may very well be that the alignment becomes incorrect.

Share this post

Link to post
Share on other sites
WitchLord    4677

I think only a low-level debugging session would allow us to identify the cause. It would be necessary to examine at exactly which location the values become incorrect and the stack becomes misaligned. 

Share this post

Link to post
Share on other sites
simong    242

Hi Andreas,


I'm afraid asm/misaligned stack/... goes a bit beyond my understanding.

I uploaded a series of screenshots showing a few more steps and some values, but as I'm not sure what I'm looking for I don't know if it's any helpful.


On the other hand what I can do is ask for some feedback on libcinder forum and try to make some people test the xcode project. Just to make sure I'm not crazy and because it might be easier to find people with the same platform/frameworks/libraries over there.


Let me know if there's something I could do.


Thanks again! 

Share this post

Link to post
Share on other sites
WitchLord    4677

From the screenshots I can see that everything is correct up until the inline assembler code executes. The values passed into the CallCDeclFunction are as they should be, which would indicate that the problem really is somewhere within the inline assembler code. 


If you can step through the inline assembler code instruction by instruction and show me the values of the affected registers, much like how you did with the C++ code before it I may be able to spot the problem. 


Perhaps if you'd allow me to login to your machine remotely (for example, using something like logmein) I could do the debugging myself.



I very much doubt the problem is related to libcinder (unless they too have some assembler code that might mess with the CPU registers).

Share this post

Link to post
Share on other sites
simong    242

Sorry for the late reply Andreas!


I finally ended up switching back to 64-bit.


I was talking about posting this to cinder forum to have people test it, just to make sure I didn't do something wrong. But as it seems to be really low level related it might be more on the compiler/xcode side... 


If you still want to access my machine, I'll be happy to find a way to do that. I can give you my email address so we can figure out how to do it.


Thanks for the help anyway!

Share this post

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this