Cocos 2dx項目lua調用OC出現卡死但不閃退的坑
阿新 • • 發佈:2018-08-10
col rgs ons dict 一個 format gen orf classname
最近新上線的一個遊戲,發現線上遊戲有部分功能在點擊的時候出現了沒有反應的情況。通過調試源碼,發現是原生OC的代碼出現了崩潰,但是比較奇怪的是線上的Bugly沒有任何記錄,這個功能屬於高頻高能,而且又是非常重要的功能,所以我下定決心查個明白。後來通過查看cocos2d_lua_bindings的源碼,發現是cocos2d_lua_bindings中的CCLuaObjcBridge.mm166行把這個崩潰給catch了。。所以質檢部門也沒發現這個錯誤,可能是以為遊戲只是卡了下,真的是坑死人不償命啊。
下面是CCLuaObjcBridge.mm的源碼
/** className methodName args*/ int LuaObjcBridge::callObjcStaticMethod(lua_State *L) { if (lua_gettop(L) != 3 || !lua_isstring(L, -3) || !lua_isstring(L, -2)) { lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorInvalidParameters); return 2; } const char *className = lua_tostring(L, -3); const char *methodName = lua_tostring(L, -2); if (!className || !methodName) { lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorInvalidParameters); return 2; } Class targetClass = NSClassFromString([NSString stringWithCString:className encoding:NSUTF8StringEncoding]);if (!targetClass) { lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorClassNotFound); return 2; } SEL methodSel; bool hasArguments = lua_istable(L, -1); if (hasArguments) { NSString *methodName_ = [NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]; methodName_ = [NSString stringWithFormat:@"%@:", methodName_]; methodSel = NSSelectorFromString(methodName_); } else { methodSel = NSSelectorFromString([NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]); } if (methodSel == (SEL)0) { lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorMethodNotFound); return 2; } NSMethodSignature *methodSig = [targetClass methodSignatureForSelector:(SEL)methodSel]; if (methodSig == nil) { lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorMethodSignature); return 2; } @try { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig]; [invocation setTarget:targetClass]; [invocation setSelector:methodSel]; NSUInteger returnLength = [methodSig methodReturnLength]; const char *returnType = [methodSig methodReturnType]; if (hasArguments) { NSMutableDictionary *dict = [NSMutableDictionary dictionary]; lua_pushnil(L); while (lua_next(L, -2)) { NSString *key = [NSString stringWithCString:lua_tostring(L, -2) encoding:NSUTF8StringEncoding]; switch (lua_type(L, -1)) { case LUA_TNUMBER: [dict setObject:[NSNumber numberWithFloat:lua_tonumber(L, -1)] forKey:key]; break; case LUA_TBOOLEAN: [dict setObject:[NSNumber numberWithBool:lua_toboolean(L, -1)] forKey:key]; break; case LUA_TSTRING: [dict setObject:[NSString stringWithCString:lua_tostring(L, -1) encoding:NSUTF8StringEncoding] forKey:key]; break; case LUA_TFUNCTION: int functionId = retainLuaFunction(L, -1, NULL); [dict setObject:[NSNumber numberWithInt:functionId] forKey:key]; break; } lua_pop(L, 1); } [invocation setArgument:&dict atIndex:2]; [invocation invoke]; } else { [invocation invoke]; } lua_pushboolean(L, 1); if (returnLength > 0) { if (strcmp(returnType, "@") == 0) { id ret; [invocation getReturnValue:&ret]; pushValue(L, ret); } else if (strcmp(returnType, "c") == 0) // BOOL { char ret; [invocation getReturnValue:&ret]; lua_pushboolean(L, ret); } else if (strcmp(returnType, "i") == 0) // int { int ret; [invocation getReturnValue:&ret]; lua_pushinteger(L, ret); } else if (strcmp(returnType, "f") == 0) // float { float ret; [invocation getReturnValue:&ret]; lua_pushnumber(L, ret); } else { NSLog(@"not support return type = %s", returnType); lua_pushnil(L); } } else { lua_pushnil(L); } return 2; } @catch (NSException *exception) //就是這處代碼導致崩潰被catch了,正確的做法應該是測試階段直接throw exception,上線後通過bugly手動上報這個exception對象
{ NSLog(@"EXCEPTION THROW: %@", exception); lua_pushboolean(L, 0); lua_pushinteger(L, kLuaBridgeErrorExceptionOccurred); return 2; } }
Cocos 2dx項目lua調用OC出現卡死但不閃退的坑