This is an automated email from the ASF dual-hosted git repository. moshen pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-weex.git
The following commit(s) were added to refs/heads/master by this push: new 1461699 [iOS] Protect for invalid JSON object on iOS13 which will crash. new 315f88f Merge pull request #2931 from wqyfavor/fix_json_crash_ios13 1461699 is described below commit 146169900bdc8093cec47817d3dccfc9d763be23 Author: qianyuan.wqy <qianyuan....@taobao.com> AuthorDate: Mon Sep 23 21:08:16 2019 +0800 [iOS] Protect for invalid JSON object on iOS13 which will crash. --- ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm | 8 ++++ ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h | 1 + ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m | 2 + ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m | 6 +++ ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h | 8 ++++ .../WeexSDK/Sources/Utility/WXConvertUtility.mm | 53 ++++++++++++++++++++++ 6 files changed, 78 insertions(+) diff --git a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm index e241609..d739d63 100644 --- a/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm +++ b/ios/sdk/WeexSDK/Sources/Bridge/WXCoreBridge.mm @@ -1302,6 +1302,7 @@ break; \ _customPages[sId] = page; } + SetConvertCurrentPage(pageId); [WXCustomPageBridge parseRenderObject:data parentRef:"" index:0 genObject:^(const std::string &ref, const std::string &type, const std::string &parentRef, std::map<std::string, std::string> *styles, std::map<std::string, std::string> *attrs, std::set<std::string> *events, int index) { if (parentRef.empty()) { // is root body @@ -1343,6 +1344,7 @@ break; \ { RenderPageCustom* page = [self getPage:pageId]; if (page && page->IsValid()) { + SetConvertCurrentPage(pageId); page->UpdateAttr([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]); } } @@ -1351,6 +1353,7 @@ break; \ { RenderPageCustom* page = [self getPage:pageId]; if (page && page->IsValid()) { + SetConvertCurrentPage(pageId); page->UpdateStyle([ref UTF8String] ?: "", [WXCustomPageBridge parseMapValuePairs:data]); } } @@ -1406,6 +1409,7 @@ break; \ if (target && target->shouldHandleModuleMethod([moduleName UTF8String] ?: "", [methodName UTF8String] ?: "")) { __block const char* seralizedArguments = nullptr; __block const char* seralizedOptions = nullptr; + SetConvertCurrentPage(pageId); ConvertToCString(arguments, ^(const char * value) { if (value != nullptr) { seralizedArguments = strdup(value); @@ -1495,6 +1499,7 @@ break; \ if (target) { __block const char* seralizedArguments = nullptr; __block const char* seralizedOptions = nullptr; + SetConvertCurrentPage(pageId); ConvertToCString(arguments, ^(const char * value) { if (value != nullptr) { seralizedArguments = strdup(value); @@ -1847,6 +1852,7 @@ static WeexCore::ScriptBridge* jsBridge = nullptr; return; } + SetConvertCurrentPage(pageId); const std::string page([pageId UTF8String] ?: ""); RenderManager::GetInstance()->CreatePage(page, [&] (RenderPage* pageInstance) -> RenderObject* { pageInstance->set_before_layout_needed(false); // we do not need before and after layout @@ -1868,11 +1874,13 @@ static WeexCore::ScriptBridge* jsBridge = nullptr; + (void)callUpdateAttrs:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data { + SetConvertCurrentPage(pageId); WeexCore::RenderManager::GetInstance()->UpdateAttr([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]); } + (void)callUpdateStyle:(NSString*)pageId ref:(NSString*)ref data:(NSDictionary*)data { + SetConvertCurrentPage(pageId); WeexCore::RenderManager::GetInstance()->UpdateStyle([pageId UTF8String] ?: "", [ref UTF8String] ?: "", [self _parseMapValuePairs:data]); } diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h index 449ab92..17fa069 100644 --- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h +++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.h @@ -107,6 +107,7 @@ typedef NS_ENUM(int, WXSDKErrCode) WX_KEY_EXCEPTION_EMPTY_SCREEN_NATIVE = -9701, WX_KEY_EXCEPTION_NO_BUNDLE_TYPE = -9801, + WX_KEY_EXCEPTION_INVALID_JSON_OBJECT = -9802, WX_KEY_EXCEPTION_HERON_ERROR = -9900, WX_KEY_EXCEPTION_HERON_RENDER_ERROR = -9901, diff --git a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m index 8d7bc9d..0f06927 100644 --- a/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m +++ b/ios/sdk/WeexSDK/Sources/Engine/WXSDKError.m @@ -105,6 +105,8 @@ @(WX_KEY_EXCEPTION_NO_BUNDLE_TYPE):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)}, + @(WX_KEY_EXCEPTION_INVALID_JSON_OBJECT):@{ERROR_TYPE:@(WX_JS_ERROR),ERROR_GROUP:@(WX_JS)}, + @(WX_KEY_EXCEPTION_HERON_ERROR):@{ERROR_TYPE:@(WX_NATIVE_ERROR),ERROR_GROUP:@(WX_NATIVE)}, @(WX_KEY_EXCEPTION_HERON_RENDER_ERROR):@{ERROR_TYPE:@(WX_RENDER_ERROR),ERROR_GROUP:@(WX_NATIVE)}, }; diff --git a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m index 1a09028..360ad4f 100644 --- a/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m +++ b/ios/sdk/WeexSDK/Sources/Model/WXSDKInstance.m @@ -49,6 +49,7 @@ #import "WXJSCoreBridge.h" #import "WXSDKInstance_performance.h" #import "WXPageEventNotifyEvent.h" +#import "WXConvertUtility.h" #import "WXCoreBridge.h" #import <WeexSDK/WXDataRenderHandler.h> @@ -599,6 +600,11 @@ typedef enum : NSUInteger { if ([configCenter respondsToSelector:@selector(configForKey:defaultValue:isDefault:)]) { BOOL enableRTLLayoutDirection = [[configCenter configForKey:@"iOS_weex_ext_config.enableRTLLayoutDirection" defaultValue:@(YES) isDefault:NULL] boolValue]; [WXUtility setEnableRTLLayoutDirection:enableRTLLayoutDirection]; + + BOOL isIOS13 = [[[UIDevice currentDevice] systemVersion] integerValue] == 13; + BOOL useMRCForInvalidJSONObject = [[configCenter configForKey:@"iOS_weex_ext_config.useMRCForInvalidJSONObject" defaultValue:@(YES) isDefault:NULL] boolValue]; + BOOL alwaysUseMRCForObjectToWeexCore = [[configCenter configForKey:@"iOS_weex_ext_config.alwaysUseMRC" defaultValue:@(NO) isDefault:NULL] boolValue]; + ConvertSwitches(isIOS13, useMRCForInvalidJSONObject, alwaysUseMRCForObjectToWeexCore); } return NO; } diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h index a5e64f5..2cd8f9b 100644 --- a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h +++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.h @@ -47,6 +47,14 @@ NSMutableArray* _Nonnull NSARRAY(std::vector<std::unordered_map<std::string, std void ConvertToCString(id _Nonnull obj, void (^ _Nonnull callback)(const char* _Nullable)); +extern "C" { + void SetConvertCurrentPage(NSString* _Nonnull pageId); + void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC); +} + +#else +void SetConvertCurrentPage(NSString* _Nonnull pageId); +void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC); #endif #endif diff --git a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm index bec9105..65d035d 100644 --- a/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm +++ b/ios/sdk/WeexSDK/Sources/Utility/WXConvertUtility.mm @@ -20,10 +20,32 @@ #import "WXConvertUtility.h" #import "WXLog.h" #import "WXAssert.h" +#import "WXExceptionUtils.h" +#import "WXSDKError.h" + #include <vector> #include <string> static NSString* const JSONSTRING_SUFFIX = @"\t\n\t\r"; +static NSString* const OBJC_MRC_SUFFIX = @"\t\t\n\r"; + +static BOOL bIsIOS13 = NO; +static BOOL bUseMRCForInvalidJSONObject = NO; +static BOOL bAlwaysUseMRC = NO; + +static NSString* sCurrentPage = nil; + +void SetConvertCurrentPage(NSString* pageId) +{ + sCurrentPage = pageId; +} + +void ConvertSwitches(BOOL isIOS13, BOOL invalidJSONObjectUseMRC, BOOL alwaysUseMRC) +{ + bIsIOS13 = isIOS13; + bUseMRCForInvalidJSONObject = invalidJSONObjectUseMRC; + bAlwaysUseMRC = alwaysUseMRC; +} #if 0 @@ -78,6 +100,28 @@ NSString* TO_JSON(id object) _detectObjectRecursion(object, nodes); #endif + if (bAlwaysUseMRC) { + return [NSString stringWithFormat:@"%p%@", (__bridge_retained void*)object, OBJC_MRC_SUFFIX]; + } + + if (bIsIOS13) { + if (![NSJSONSerialization isValidJSONObject:object]) { + [WXExceptionUtils commitCriticalExceptionRT:sCurrentPage + errCode:[NSString stringWithFormat:@"%d", WX_KEY_EXCEPTION_INVALID_JSON_OBJECT] + function:@"" + exception:@"Invalid JSON object." + extParams:nil]; + + // Report for instance. + if (bUseMRCForInvalidJSONObject) { + return [NSString stringWithFormat:@"%p%@", (__bridge_retained void*)object, OBJC_MRC_SUFFIX]; + } + else { + return nil; + } + } + } + NSError *error = nil; NSData *data = [NSJSONSerialization dataWithJSONObject:object options:0 @@ -126,6 +170,15 @@ id TO_OBJECT(NSString* s) WXAssert(NO, @"Fail to convert json to object. %@", exception); } } + else if ([s hasSuffix:OBJC_MRC_SUFFIX]) { + NSScanner* scanner = [NSScanner scannerWithString:s]; + unsigned long long address = 0; + [scanner scanHexLongLong:&address]; + if (address != 0) { + return (__bridge_transfer id)((void*)address); + } + } + return s; // return s instead }