已开启
fix: WantParams ToString/Serialize crash on invalid UTF-8 bytes #875
fix: WantParams ToString/Serialize crash on invalid UTF-8 bytes #875
已开启
SkyQAQ创建于 8 天前
10 个文件变更+153-7
@@ -238,7 +238,7 @@ const std::string Configuration::GetName() const
238 json configArray(configParameter_);238 json configArray(configParameter_);
239 std::string configArrayStr = "";239 std::string configArrayStr = "";
240 try {240 try {
241- configArrayStr = configArray.dump();241+ configArrayStr = configArray.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore);
242 } catch (...) {242 } catch (...) {
243 ABILITYBASE_LOGE("failed to dump GetName");243 ABILITYBASE_LOGE("failed to dump GetName");
244 }244 }
@@ -98,7 +98,7 @@ std::string PageNodeInfo::ToJsonString() const
98 {PAGE_NODE_INFO_RECT, rect.ToJsonString()},98 {PAGE_NODE_INFO_RECT, rect.ToJsonString()},
99 {PAGE_NODE_INFO_IS_FOCUS, isFocus}99 {PAGE_NODE_INFO_IS_FOCUS, isFocus}
100 };100 };
101- return jsonObject.dump();101+ return jsonObject.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore);
102}102}
103} // namespace AbilityBase103} // namespace AbilityBase
104} // namespace OHOS104} // namespace OHOS
@@ -89,7 +89,7 @@ std::string ViewData::ToJsonString() const
89 {VIEW_DATA_OTHER_ACCOUNT, isOtherAccount},89 {VIEW_DATA_OTHER_ACCOUNT, isOtherAccount},
90 {VIEW_DATA_PAGE_RECT, pageRect.ToJsonString()}90 {VIEW_DATA_PAGE_RECT, pageRect.ToJsonString()}
91 };91 };
92- return jsonObject.dump();92+ return jsonObject.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore);
93}93}
94} // namespace AbilityBase94} // namespace AbilityBase
95} // namespace OHOS95} // namespace OHOS
@@ -235,7 +235,9 @@ void ParseWantParamsFromJsonString(const std::string &jsonString, WantParams &wa
235template<typename JsonType>235template<typename JsonType>
236void from_json(const JsonType &jsonObject, WantParams &wantParams)236void from_json(const JsonType &jsonObject, WantParams &wantParams)
237{237{
238- ParseWantParamsFromJsonString(jsonObject.dump(), wantParams);238+ using ErrorHandler = typename JsonType::error_handler_t;
239+ ParseWantParamsFromJsonString(
240+ jsonObject.dump(-1, ' ', false, ErrorHandler::ignore), wantParams);
239}241}
240 242 
241template<typename JsonType>243template<typename JsonType>
@@ -2371,7 +2371,7 @@ std::string WantParams::ToString() const
2371{2371{
2372 nlohmann::json jsonObject;2372 nlohmann::json jsonObject;
2373 WantParamsToJson(jsonObject, *this);2373 WantParamsToJson(jsonObject, *this);
2374- return jsonObject.dump();2374+ return jsonObject.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore);
2375}2375}
2376 2376 
2377void ParseWantParamsFromJsonString(const std::string &jsonString, WantParams &wantParams)2377void ParseWantParamsFromJsonString(const std::string &jsonString, WantParams &wantParams)
@@ -2386,7 +2386,8 @@ void ParseWantParamsFromJsonString(const std::string &jsonString, WantParams &wa
2386 2386 
2387void from_json(const nlohmann::json &jsonObject, WantParams &wantParams)2387void from_json(const nlohmann::json &jsonObject, WantParams &wantParams)
2388{2388{
2389- ParseWantParamsFromJsonString(jsonObject.dump(), wantParams);2389+ ParseWantParamsFromJsonString(
2390+ jsonObject.dump(-1, ' ', false, nlohmann::json::error_handler_t::ignore), wantParams);
2390}2391}
2391 2392 
2392void to_json(nlohmann::json &jsonObject, const WantParams &wantParams)2393void to_json(nlohmann::json &jsonObject, const WantParams &wantParams)
@@ -253,7 +253,7 @@ bool Serialize(const WantParams &wp, std::string &out)
253 253 
254 Json envelope = Json::object();254 Json envelope = Json::object();
255 envelope[ENVELOPE_KEY] = std::move(params);255 envelope[ENVELOPE_KEY] = std::move(params);
256- out = envelope.dump();256+ out = envelope.dump(-1, ' ', false, Json::error_handler_t::ignore);
257 return true;257 return true;
258 } catch (const Json::exception &e) {258 } catch (const Json::exception &e) {
259 ABILITYBASE_LOGE("serialize failed, json exception id=%{public}d", e.id);259 ABILITYBASE_LOGE("serialize failed, json exception id=%{public}d", e.id);
@@ -1186,5 +1186,27 @@ HWTEST_F(PageNodeInfoTest, ToJsonString_004, TestSize.Level1)
1186 nlohmann::json jsonResult = nlohmann::json::parse(result);1186 nlohmann::json jsonResult = nlohmann::json::parse(result);
1187 EXPECT_FALSE(jsonResult.is_null());1187 EXPECT_FALSE(jsonResult.is_null());
1188}1188}
1189+ 
1190+/**
1191+ * @tc.name: ToJsonString_InvalidUtf8_0100
1192+ * @tc.desc: Verify ToJsonString survives invalid UTF-8 bytes in string fields.
1193+ * @tc.type: FUNC
1194+ */
1195+HWTEST_F(PageNodeInfoTest, ToJsonString_InvalidUtf8_0100, TestSize.Level1)
1196+{
1197+ PageNodeInfo testNode;
1198+ std::string invalidUtf8;
1199+ invalidUtf8.push_back(static_cast<char>(0xFF));
1200+ invalidUtf8.push_back(static_cast<char>(0xFE));
1201+ invalidUtf8.push_back(static_cast<char>(0x80));
1202+ testNode.value = invalidUtf8;
1203+ testNode.tag = "valid";
1204+ 
1205+ std::string result = testNode.ToJsonString();
1206+ nlohmann::json jsonResult = nlohmann::json::parse(result);
1207+ ASSERT_FALSE(jsonResult.is_discarded());
1208+ ASSERT_TRUE(jsonResult.contains(PAGE_NODE_INFO_TAG));
1209+ EXPECT_EQ(jsonResult[PAGE_NODE_INFO_TAG], "valid");
1210+}
1189} // namespace AbilityBase1211} // namespace AbilityBase
1190} // namespace OHOS1212} // namespace OHOS
@@ -785,5 +785,27 @@ HWTEST_F(ViewDataTest, ToJsonString_1010, TestSize.Level1)
785 EXPECT_NE(jsonResult[VIEW_DATA_ABILITY_NAME], "Ability1\twith\ttabs");785 EXPECT_NE(jsonResult[VIEW_DATA_ABILITY_NAME], "Ability1\twith\ttabs");
786 EXPECT_EQ(jsonResult[VIEW_DATA_PAGE_URL], "pages/\\escaped");786 EXPECT_EQ(jsonResult[VIEW_DATA_PAGE_URL], "pages/\\escaped");
787}787}
788+ 
789+/**
790+ * @tc.name: ToJsonString_InvalidUtf8_0100
791+ * @tc.desc: Verify ToJsonString survives invalid UTF-8 bytes in string fields.
792+ * @tc.type: FUNC
793+ */
794+HWTEST_F(ViewDataTest, ToJsonString_InvalidUtf8_0100, TestSize.Level1)
795+{
796+ ViewData viewData;
797+ std::string invalidUtf8;
798+ invalidUtf8.push_back(static_cast<char>(0xFF));
799+ invalidUtf8.push_back(static_cast<char>(0xFE));
800+ invalidUtf8.push_back(static_cast<char>(0x80));
801+ viewData.bundleName = invalidUtf8;
802+ viewData.pageUrl = "valid";
803+ 
804+ std::string result = viewData.ToJsonString();
805+ nlohmann::json jsonResult = nlohmann::json::parse(result);
806+ ASSERT_FALSE(jsonResult.is_discarded());
807+ ASSERT_TRUE(jsonResult.contains(VIEW_DATA_PAGE_URL));
808+ EXPECT_EQ(jsonResult[VIEW_DATA_PAGE_URL], "valid");
809+}
788} // namespace AbilityBase810} // namespace AbilityBase
789} // namespace OHOS811} // namespace OHOS
@@ -1446,6 +1446,56 @@ HWTEST_F(WantParamsBaseTest, AaFwk_WantParams_ToString_Nested_0100, Function | M
1446 EXPECT_EQ(jsonObj["nested"]["innerKey"], "innerValue");1446 EXPECT_EQ(jsonObj["nested"]["innerKey"], "innerValue");
1447}1447}
1448 1448 
1449+/**
1450+ * @tc.number: AaFwk_WantParams_ToString_InvalidUtf8_0100
1451+ * @tc.name: ToString
1452+ * @tc.desc: Verify ToString survives param values that are not valid UTF-8. The value
1453+ * may come from an untrusted Parcel across processes, so ToString must not
1454+ * throw on invalid UTF-8 bytes. In the original code, dump() uses the strict
1455+ * error handler and throws nlohmann::json::type_error (id 316) which, under
1456+ * -fno-exceptions, terminates the process. After the fix (error_handler_t::
1457+ * replace), ToString returns parseable JSON with the bad bytes replaced.
1458+ */
1459+HWTEST_F(WantParamsBaseTest, AaFwk_WantParams_ToString_InvalidUtf8_0100, Function | MediumTest | Level1)
1460+{
1461+ WantParams params;
1462+ std::string invalidUtf8;
1463+ invalidUtf8.push_back(static_cast<char>(0xFF));
1464+ invalidUtf8.push_back(static_cast<char>(0xFE));
1465+ invalidUtf8.push_back(static_cast<char>(0x80));
1466+ params.SetParam("badKey", OHOS::AAFwk::String::Box(invalidUtf8));
1467+ 
1468+ std::string jsonString = params.ToString();
1469+ auto jsonObj = nlohmann::json::parse(jsonString, nullptr, false);
1470+ ASSERT_FALSE(jsonObj.is_discarded());
1471+ ASSERT_TRUE(jsonObj.contains("badKey"));
1472+ EXPECT_TRUE(jsonObj["badKey"].is_string());
1473+}
1474+ 
1475+/**
1476+ * @tc.number: AaFwk_WantParams_ToString_InvalidUtf8_0200
1477+ * @tc.name: ToString
1478+ * @tc.desc: Verify ToString survives invalid UTF-8 bytes embedded inside a longer
1479+ * string (mixed with valid multi-byte UTF-8). Guards against the same
1480+ * strict-error-handler throw on dump().
1481+ */
1482+HWTEST_F(WantParamsBaseTest, AaFwk_WantParams_ToString_InvalidUtf8_0200, Function | MediumTest | Level1)
1483+{
1484+ WantParams params;
1485+ std::string mixed = "hello";
1486+ mixed.push_back(static_cast<char>(0xE4)); // lead byte of a 3-byte seq
1487+ mixed.push_back(static_cast<char>(0xBD)); // continuation, but sequence truncated
1488+ mixed.push_back(static_cast<char>(0xFF));
1489+ mixed += "world";
1490+ params.SetParam("mixedKey", OHOS::AAFwk::String::Box(mixed));
1491+ 
1492+ std::string jsonString = params.ToString();
1493+ auto jsonObj = nlohmann::json::parse(jsonString, nullptr, false);
1494+ ASSERT_FALSE(jsonObj.is_discarded());
1495+ ASSERT_TRUE(jsonObj.contains("mixedKey"));
1496+ EXPECT_TRUE(jsonObj["mixedKey"].is_string());
1497+}
1498+ 
1449/**1499/**
1450 * @tc.number: AaFwk_WantParams_PublicReadFromParcel_01001500 * @tc.number: AaFwk_WantParams_PublicReadFromParcel_0100
1451 * @tc.name: PublicReadFromParcel1501 * @tc.name: PublicReadFromParcel
@@ -1265,3 +1265,52 @@ HWTEST_F(WantParamWrapperJsonTest, Want_Param_Wrapper_Json_3990, TestSize.Level1
1265 EXPECT_FALSE(WantParamWrapperJson::Serialize(overLimit, serialized));1265 EXPECT_FALSE(WantParamWrapperJson::Serialize(overLimit, serialized));
1266 EXPECT_EQ(serialized, "unchanged");1266 EXPECT_EQ(serialized, "unchanged");
1267}1267}
1268+ 
1269+/**
1270+ * @tc.number: Want_Param_Wrapper_Json_4000
1271+ * @tc.name: Serialize survives invalid UTF-8 bytes
1272+ * @tc.desc: Verify WantParamWrapperJson::Serialize does not throw when a string
1273+ * param contains bytes that are not valid UTF-8. The original code calls
1274+ * envelope.dump() with the strict error handler, which throws
1275+ * nlohmann::json::type_error 316 and terminates. After the fix
1276+ * (error_handler_t::ignore), Serialize succeeds and returns valid JSON.
1277+ */
1278+HWTEST_F(WantParamWrapperJsonTest, Want_Param_Wrapper_Json_4000, TestSize.Level1)
1279+{
1280+ WantParams wp;
1281+ std::string invalidUtf8;
1282+ invalidUtf8.push_back(static_cast<char>(0xFF));
1283+ invalidUtf8.push_back(static_cast<char>(0xFE));
1284+ invalidUtf8.push_back(static_cast<char>(0x80));
1285+ wp.SetParam("k", String::Box(invalidUtf8));
1286+ 
1287+ std::string serialized;
1288+ EXPECT_TRUE(WantParamWrapperJson::Serialize(wp, serialized));
1289+ 
1290+ WantParams out;
1291+ EXPECT_TRUE(WantParamWrapperJson::Parse(serialized, out));
1292+}
1293+ 
1294+/**
1295+ * @tc.number: Want_Param_Wrapper_Json_4010
1296+ * @tc.name: Serialize survives invalid UTF-8 in nested WantParams
1297+ * @tc.desc: Same as 4000 but with invalid UTF-8 inside a nested WantParams,
1298+ * which exercises the recursive BuildParamsJson path.
1299+ */
1300+HWTEST_F(WantParamWrapperJsonTest, Want_Param_Wrapper_Json_4010, TestSize.Level1)
1301+{
1302+ WantParams inner;
1303+ std::string invalidUtf8;
1304+ invalidUtf8.push_back(static_cast<char>(0xFF));
1305+ invalidUtf8.push_back(static_cast<char>(0xFE));
1306+ inner.SetParam("inner", String::Box(invalidUtf8));
1307+ 
1308+ WantParams wp;
1309+ wp.SetParam("nested", WantParamWrapper::Box(std::move(inner)));
1310+ 
1311+ std::string serialized;
1312+ EXPECT_TRUE(WantParamWrapperJson::Serialize(wp, serialized));
1313+ 
1314+ WantParams out;
1315+ EXPECT_TRUE(WantParamWrapperJson::Parse(serialized, out));
1316+}