Advertisement

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

Started by February 16, 2014 11:34 AM
12 comments, last by simong 10 years, 8 months ago

Hi,

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(),
                                    asBEHAVE_CONSTRUCT,
                                    ( "void f("+type+","+type+")" ).c_str(),
                                    asFUNCTION((BindingHelper::constructor<ci::Vec2<T>,T,T>)),
                                    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!

Simon.

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

Advertisement

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?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Can you also show me the string returned by the global function asGetLibraryOptions()? It will let me know if the as_config.h is detecting the correct platform configuration.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

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!

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?

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement

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:

https://www.dropbox.com/s/eed2g944afig8ce/scriptstdstring%20assembly.asm

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/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__functional_base:344
#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/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1059
#15	0x00082220 in std::__1::function<void (std::__1::shared_ptr<cinder::DataSource>)>::operator()(std::__1::shared_ptr<cinder::DataSource>) const at /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/functional:1435
#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/AppImplCocoaBasic.mm:91
#21	0x90c6d692 in __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke ()
#22	0x98c077e4 in __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ()
#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().


pthread_rwlock_rdlock(&lock);

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.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks a lot for taking the time and being so active!

Here's the as_callfunc_x86 assembler code: https://www.dropbox.com/s/h0auyevxixwple0/as_callfunc_x86.cpp

I'll try to disable all optimisations and see if it change anything. I'll let you know!

I don't see anything wrong with the assembler code for as_callfunc_x86.cpp. It should work.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement