From 93dc3f5af29800805d0a4d71f46a5471c1b2756a Mon Sep 17 00:00:00 2001 From: wwwcg Date: Thu, 28 Mar 2024 17:11:58 +0800 Subject: [PATCH] fix(ios): fix conversion crash from oc object to CtxValue --- driver/js/src/napi/jsc/jsc_ctx.cc | 5 +- framework/ios/utils/NSObject+CtxValue.mm | 9 ++- tests/ios/HippyOC2CtxValueTest.mm | 89 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) create mode 100644 tests/ios/HippyOC2CtxValueTest.mm diff --git a/driver/js/src/napi/jsc/jsc_ctx.cc b/driver/js/src/napi/jsc/jsc_ctx.cc index a831e84a1c9..c7d1be501ce 100644 --- a/driver/js/src/napi/jsc/jsc_ctx.cc +++ b/driver/js/src/napi/jsc/jsc_ctx.cc @@ -794,7 +794,8 @@ std::shared_ptr JSCCtx::CreateObject(const std::unordered_map(it.second); if (!ctx_value) { auto error = CreateException("CreateObject ctx_value is nullptr"); - return nullptr; + SetException(std::static_pointer_cast(error)); + continue; } JSObjectSetProperty(context_, obj, object_key, ctx_value->value_, kJSPropertyAttributeNone, &exception); if (exception) { @@ -817,7 +818,7 @@ std::shared_ptr JSCCtx::CreateArray(size_t count, JSValueRef values[count]; // NOLINT(runtime/arrays) for (size_t i = 0; i < count; i++) { auto ele_value = std::static_pointer_cast(array[i]); - values[i] = ele_value->value_; + values[i] = ele_value ? ele_value->value_ : nullptr; } JSValueRef exception = nullptr; diff --git a/framework/ios/utils/NSObject+CtxValue.mm b/framework/ios/utils/NSObject+CtxValue.mm index e196e04b8cf..1ee6b0c3fef 100644 --- a/framework/ios/utils/NSObject+CtxValue.mm +++ b/framework/ios/utils/NSObject+CtxValue.mm @@ -32,7 +32,7 @@ @implementation NSObject (CtxValue) - (CtxValuePtr)convertToCtxValue:(const CtxPtr &)context; { @autoreleasepool { - HippyLogWarn(@"%@ must implemente convertToCtxValue method", NSStringFromClass([self class])); + HippyLogWarn(@"%@ No convertToCtxValue method", NSStringFromClass([self class])); std::unordered_map valueMap; return context->CreateObject(valueMap); } @@ -87,7 +87,9 @@ - (CtxValuePtr)convertToCtxValue:(const CtxPtr &)context { id value = [self objectForKey:key]; auto keyPtr = [key convertToCtxValue:context]; auto valuePtr = [value convertToCtxValue:context]; - valueMap[keyPtr] = valuePtr; + if (keyPtr && valuePtr) { + valueMap[keyPtr] = valuePtr; + } } return context->CreateObject(valueMap); } @@ -99,6 +101,9 @@ @implementation NSData (CtxValue) - (CtxValuePtr)convertToCtxValue:(const CtxPtr &)context { size_t bufferLength = [self length]; + if (bufferLength == 0) { + return context->CreateNull(); + } void *buffer = malloc(bufferLength); if (buffer) { [self getBytes:buffer length:bufferLength]; diff --git a/tests/ios/HippyOC2CtxValueTest.mm b/tests/ios/HippyOC2CtxValueTest.mm new file mode 100644 index 00000000000..eb4e3c09c2c --- /dev/null +++ b/tests/ios/HippyOC2CtxValueTest.mm @@ -0,0 +1,89 @@ +/*! + * iOS SDK + * + * Tencent is pleased to support the open source community by making + * Hippy available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import +#import +#import "driver/engine.h" +#import "driver/scope.h" + +@interface HippyOC2CtxValueTest : XCTestCase + +@end + +@implementation HippyOC2CtxValueTest + +- (void)setUp { + // Put setup code here. This method is called before the invocation of each test method in the class. +} + +- (void)tearDown { + // Put teardown code here. This method is called after the invocation of each test method in the class. +} + +- (void)testOCObject2CtxValue { + auto engine = [[HippyJSEnginesMapper defaultInstance] createJSEngineResourceForKey:@"testKey"]; + auto scope = engine->GetEngine()->CreateScope("testKey"); + + XCTestExpectation *expectation = [self expectationWithDescription:@"ToCtxValue"]; + engine->GetEngine()->GetJsTaskRunner()->PostTask([scope, expectation](){ + scope->CreateContext(); + auto context = scope->GetContext(); + + NSMutableDictionary *testDic = [NSMutableDictionary dictionary]; + NSMutableDictionary *nestedDic = [NSMutableDictionary dictionary]; + nestedDic[@"testZeroData"] = [NSData data]; + nestedDic[@"testNumber"] = @200; + nestedDic[@"testNull"] = [NSNull null]; + nestedDic[@"testString"] = @""; + nestedDic[@"testString1"] = @"0"; + nestedDic[@"testArray"] = @[]; + nestedDic[@"testError"] = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:nil]; + nestedDic[@"testDictionary"] = @{}; + nestedDic[@"testURL"] = [NSURL URLWithString:@""]; + std::shared_ptr ctxValue = [nestedDic convertToCtxValue:context]; + XCTAssert(ctxValue != nullptr); + + testDic[@"testDic"] = nestedDic; + ctxValue = [testDic convertToCtxValue:context]; + XCTAssert(ctxValue != nullptr); + + ctxValue = [@[testDic, testDic, testDic] convertToCtxValue:context]; + XCTAssert(ctxValue != nullptr); + + NSMutableArray *testArr = [NSMutableArray array]; + [testArr addObject:[NSData data]]; + [testArr addObject:[NSDate date]]; + [testArr addObject:[NSHashTable weakObjectsHashTable]]; + [testArr addObject:[NSHTTPURLResponse new]]; + XCTAssert([testArr convertToCtxValue:context] != nullptr); + + [expectation fulfill]; + }); + + [self waitForExpectationsWithTimeout:10 handler:^(NSError *error) { + NSLog(@"%@", error); + }]; +} + + +@end