Add additional check on float precision after parsing, only compile the

value when precision is not lost.

Bug: b/69347762
Test: Verified affected atests pass
Change-Id: I8e4fcd420a924f0e949bfd3a8aae23d1e7d582b1
This commit is contained in:
Brandon Liu
2023-03-31 22:37:42 +00:00
parent 00558ac53a
commit f24b9a438d
4 changed files with 40 additions and 4 deletions

View File

@@ -670,8 +670,19 @@ std::unique_ptr<Item> TryParseItemForAttribute(
// Try parsing this as a float.
auto floating_point = TryParseFloat(value);
if (floating_point) {
// Only check if the parsed result lost precision when the parsed item is
// android::Res_value::TYPE_FLOAT and there is other possible types saved in type_mask, like
// ResTable_map::TYPE_INTEGER.
if (type_mask & AndroidTypeToAttributeTypeMask(floating_point->value.dataType)) {
return std::move(floating_point);
const bool mayOnlyBeFloat = (type_mask & ~float_mask) == 0;
const bool parsedAsFloat = floating_point->value.dataType == android::Res_value::TYPE_FLOAT;
if (!mayOnlyBeFloat && parsedAsFloat) {
if (floating_point->toPrettyString() == value.data()) {
return std::move(floating_point);
}
} else {
return std::move(floating_point);
}
}
}
}

View File

@@ -228,6 +228,21 @@ TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) {
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
}
TEST(ResourceUtilsTest, FloatAndBigIntegerParsedCorrectly) {
const float expected_float = 0.125f;
const uint32_t expected_float_flattened = *(uint32_t*)&expected_float;
EXPECT_THAT(ResourceUtils::TryParseItemForAttribute("0.125", ResTable_map::TYPE_FLOAT),
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened))));
EXPECT_EQ(ResourceUtils::TryParseItemForAttribute("1099511627776", ResTable_map::TYPE_INTEGER),
std::unique_ptr<Item>(nullptr));
const float big_float = 1099511627776.0f;
const uint32_t big_flattened = *(uint32_t*)&big_float;
EXPECT_THAT(ResourceUtils::TryParseItemForAttribute("1099511627776", ResTable_map::TYPE_FLOAT),
Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, big_flattened))));
}
TEST(ResourceUtilsTest, ParseSdkVersionWithCodename) {
EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q"), Eq(std::optional<int>(10000)));
EXPECT_THAT(ResourceUtils::ParseSdkVersion("Q.fingerprint"), Eq(std::optional<int>(10000)));

View File

@@ -22,12 +22,12 @@
#include <set>
#include <sstream>
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "Resource.h"
#include "ResourceUtils.h"
#include "ValueVisitor.h"
#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "io/StringStream.h"
#include "util/Util.h"
using ::aapt::text::Printer;
@@ -487,6 +487,15 @@ void BinaryPrimitive::PrettyPrint(Printer* printer) const {
}
}
std::string BinaryPrimitive::toPrettyString() const {
std::string str;
io::StringOutputStream out(&str);
text::Printer printer(&out);
this->PrettyPrint(&printer);
out.Flush();
return str;
}
Attribute::Attribute(uint32_t t)
: type_mask(t),
min_int(std::numeric_limits<int32_t>::min()),

View File

@@ -285,6 +285,7 @@ struct BinaryPrimitive : public TransformableItem<BinaryPrimitive, BaseItem<Bina
bool Flatten(android::Res_value* out_value) const override;
void Print(std::ostream* out) const override;
void PrettyPrint(text::Printer* printer) const override;
std::string toPrettyString() const;
};
struct Attribute : public TransformableValue<Attribute, BaseValue<Attribute>> {