diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/literal.cc | 43 | ||||
-rw-r--r-- | src/literal.h | 8 | ||||
-rw-r--r-- | src/test-literal.cc | 130 | ||||
-rw-r--r-- | src/wast-parser.cc | 50 |
4 files changed, 190 insertions, 41 deletions
diff --git a/src/literal.cc b/src/literal.cc index 3560a451..4c367ed9 100644 --- a/src/literal.cc +++ b/src/literal.cc @@ -21,6 +21,8 @@ #include <cmath> #include <cstdlib> #include <cstring> +#include <limits> +#include <type_traits> namespace wabt { @@ -620,10 +622,12 @@ Result ParseInt64(const char* s, return result; } -Result ParseInt32(const char* s, - const char* end, - uint32_t* out, - ParseIntType parse_type) { +template <typename U> +Result ParseInt(const char* s, + const char* end, + U* out, + ParseIntType parse_type) { + typedef typename std::make_signed<U>::type S; uint64_t value; bool has_sign = false; if (*s == '-' || *s == '+') { @@ -638,20 +642,41 @@ Result ParseInt32(const char* s, CHECK_RESULT(ParseUint64(s, end, &value)); if (has_sign) { - // abs(INT32_MIN) == INT32_MAX + 1. - if (value > static_cast<uint64_t>(INT32_MAX) + 1) { + // abs(INTN_MIN) == INTN_MAX + 1. + if (value > static_cast<uint64_t>(std::numeric_limits<S>::max()) + 1) { return Result::Error; } - value = UINT32_MAX - value + 1; + value = std::numeric_limits<U>::max() - value + 1; } else { - if (value > static_cast<uint64_t>(UINT32_MAX)) { + if (value > static_cast<uint64_t>(std::numeric_limits<U>::max())) { return Result::Error; } } - *out = static_cast<uint32_t>(value); + *out = static_cast<U>(value); return Result::Ok; } +Result ParseInt8(const char* s, + const char* end, + uint8_t* out, + ParseIntType parse_type) { + return ParseInt(s, end, out, parse_type); +} + +Result ParseInt16(const char* s, + const char* end, + uint16_t* out, + ParseIntType parse_type) { + return ParseInt(s, end, out, parse_type); +} + +Result ParseInt32(const char* s, + const char* end, + uint32_t* out, + ParseIntType parse_type) { + return ParseInt(s, end, out, parse_type); +} + Result ParseFloat(LiteralType literal_type, const char* s, const char* end, diff --git a/src/literal.h b/src/literal.h index 40b395ed..b1315a1a 100644 --- a/src/literal.h +++ b/src/literal.h @@ -49,6 +49,14 @@ enum class ParseIntType { #define WABT_MAX_DOUBLE_HEX 40 Result ParseHexdigit(char c, uint32_t* out); +Result ParseInt8(const char* s, + const char* end, + uint8_t* out, + ParseIntType parse_type); +Result ParseInt16(const char* s, + const char* end, + uint16_t* out, + ParseIntType parse_type); Result ParseInt32(const char* s, const char* end, uint32_t* out, diff --git a/src/test-literal.cc b/src/test-literal.cc index 269470bd..e094d879 100644 --- a/src/test-literal.cc +++ b/src/test-literal.cc @@ -62,6 +62,18 @@ void AssertIntEquals(T expected, } } +void AssertInt8Equals(uint8_t expected, + const char* s, + ParseIntTypeCombo parse_type = Both) { + AssertIntEquals(expected, s, ParseInt8, parse_type); +} + +void AssertInt16Equals(uint16_t expected, + const char* s, + ParseIntTypeCombo parse_type = Both) { + AssertIntEquals(expected, s, ParseInt16, parse_type); +} + void AssertInt32Equals(uint32_t expected, const char* s, ParseIntTypeCombo parse_type = Both) { @@ -74,6 +86,28 @@ void AssertInt64Equals(uint64_t expected, AssertIntEquals(expected, s, ParseInt64, parse_type); } +void AssertInt8Fails(const char* s) { + const char* const end = s + strlen(s); + uint8_t actual; + ASSERT_EQ(Result::Error, + ParseInt8(s, end, &actual, ParseIntType::SignedAndUnsigned)) + << s; + ASSERT_EQ(Result::Error, + ParseInt8(s, end, &actual, ParseIntType::UnsignedOnly)) + << s; +} + +void AssertInt16Fails(const char* s) { + const char* const end = s + strlen(s); + uint16_t actual; + ASSERT_EQ(Result::Error, + ParseInt16(s, end, &actual, ParseIntType::SignedAndUnsigned)) + << s; + ASSERT_EQ(Result::Error, + ParseInt16(s, end, &actual, ParseIntType::UnsignedOnly)) + << s; +} + void AssertInt32Fails(const char* s) { const char* const end = s + strlen(s); uint32_t actual; @@ -139,6 +173,102 @@ void AssertHexDoubleFails(const char* s) { } // end anonymous namespace +TEST(ParseInt8, Both) { + AssertInt8Equals(0, "0"); + AssertInt8Equals(100, "100"); + AssertInt8Equals(123, "123"); + AssertInt8Equals(127, "127"); + AssertInt8Equals(255, "255"); + AssertInt8Equals(0xca, "0xca"); + AssertInt8Equals(0x7f, "0x7f"); + AssertInt8Equals(0x80, "0x80"); + AssertInt8Equals(0xff, "0xff"); +} + +TEST(ParseInt8, SignedAndUnsigned) { + AssertInt8Equals(128, "-128", SignedAndUnsigned); + AssertInt8Equals(-0x80, "-0x80", SignedAndUnsigned); + AssertInt8Equals(255, "-1", SignedAndUnsigned); + AssertInt8Equals(-1, "-0x1", SignedAndUnsigned); + AssertInt8Equals(1, "+1", SignedAndUnsigned); + AssertInt8Equals(-0x7b, "-0x7B", SignedAndUnsigned); + AssertInt8Equals(0xab, "+0xab", SignedAndUnsigned); +} + +TEST(ParseInt8, Invalid) { + AssertInt8Fails(""); + AssertInt8Fails("-100hello"); + AssertInt8Fails("0XAB"); + AssertInt8Fails("0xga"); + AssertInt8Fails("two"); +} + +TEST(ParseInt8, Underscores) { + AssertInt8Equals(123, "12_3", Both); + AssertInt8Equals(123, "+12_3", SignedAndUnsigned); + AssertInt8Equals(-123, "-1_23", SignedAndUnsigned); + AssertInt8Equals(19, "1______9", Both); + AssertInt8Equals(0xab, "0xa_b", Both); + AssertInt8Equals(0xab, "+0xa_b", SignedAndUnsigned); + AssertInt8Equals(-0x7b, "-0x7_b", SignedAndUnsigned); +} + +TEST(ParseInt8, Overflow) { + AssertInt8Fails("256"); + AssertInt8Fails("-129"); + AssertInt8Fails("0x100"); + AssertInt8Fails("-0x81"); + AssertInt8Fails("1231231231231231231231"); +} + +TEST(ParseInt16, Both) { + AssertInt16Equals(0, "0"); + AssertInt16Equals(1000, "1000"); + AssertInt16Equals(12345, "12345"); + AssertInt16Equals(32767, "32767"); + AssertInt16Equals(65535, "65535"); + AssertInt16Equals(0xcafe, "0xcafe"); + AssertInt16Equals(0x7fff, "0x7fff"); + AssertInt16Equals(0x8000, "0x8000"); + AssertInt16Equals(0xffff, "0xffff"); +} + +TEST(ParseInt16, SignedAndUnsigned) { + AssertInt16Equals(32768, "-32768", SignedAndUnsigned); + AssertInt16Equals(-0x8000, "-0x8000", SignedAndUnsigned); + AssertInt16Equals(65535, "-1", SignedAndUnsigned); + AssertInt16Equals(-1, "-0x1", SignedAndUnsigned); + AssertInt16Equals(1, "+1", SignedAndUnsigned); + AssertInt16Equals(-0x7bcd, "-0x7BCD", SignedAndUnsigned); + AssertInt16Equals(0xabcd, "+0xabcd", SignedAndUnsigned); +} + +TEST(ParseInt16, Invalid) { + AssertInt16Fails(""); + AssertInt16Fails("-100hello"); + AssertInt16Fails("0XABCD"); + AssertInt16Fails("0xgabb"); + AssertInt16Fails("two"); +} + +TEST(ParseInt16, Underscores) { + AssertInt16Equals(12345, "12_345", Both); + AssertInt16Equals(12345, "+12_345", SignedAndUnsigned); + AssertInt16Equals(-12345, "-123_45", SignedAndUnsigned); + AssertInt16Equals(19, "1______9", Both); + AssertInt16Equals(0xabcd, "0xa_b_c_d", Both); + AssertInt16Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned); + AssertInt16Equals(-0x7bcd, "-0x7_b_c_d", SignedAndUnsigned); +} + +TEST(ParseInt16, Overflow) { + AssertInt16Fails("65536"); + AssertInt16Fails("-32769"); + AssertInt16Fails("0x10000"); + AssertInt16Fails("-0x8001"); + AssertInt16Fails("1231231231231231231231"); +} + TEST(ParseInt32, Both) { AssertInt32Equals(0, "0"); AssertInt32Equals(1000, "1000"); diff --git a/src/wast-parser.cc b/src/wast-parser.cc index 92beffcc..98c22967 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1791,47 +1791,33 @@ Result WastParser::ParseSimdV128Const(Const* const_, TokenType token_type) { // the array of bytes: if (integer) { switch(lane_count) { - case 16: { - int32_t value; - result = ParseInt32(s, end, Bitcast<uint32_t*>(&value), ParseIntType::SignedAndUnsigned); - if (value < static_cast<int32_t>(std::numeric_limits<int8_t>::min()) || - value > static_cast<int32_t>(std::numeric_limits<uint8_t>::max())) { - Error(loc, "literal \"%s\" out-of-bounds of i8", literal.text.c_str()); - return Result::Error; - } - *lane_ptr = static_cast<uint8_t>(value); + case 16: + result = ParseInt8(s, end, reinterpret_cast<uint8_t*>(lane_ptr), + ParseIntType::SignedAndUnsigned); break; - } - case 8: { - int32_t value; - result = ParseInt32(s, end, Bitcast<uint32_t*>(&value), ParseIntType::SignedAndUnsigned); - if (value < static_cast<int32_t>(std::numeric_limits<int16_t>::min()) || - value > static_cast<int32_t>(std::numeric_limits<uint16_t>::max())) { - Error(loc, "literal \"%s\" out-of-bounds of i16", literal.text.c_str()); - return Result::Error; - } - *lane_ptr = static_cast<uint16_t>(value); + case 8: + result = ParseInt16(s, end, reinterpret_cast<uint16_t*>(lane_ptr), + ParseIntType::SignedAndUnsigned); break; - } - case 4: { - result = ParseInt32(s, end, Bitcast<uint32_t*>(lane_ptr), ParseIntType::SignedAndUnsigned); + case 4: + result = ParseInt32(s, end, reinterpret_cast<uint32_t*>(lane_ptr), + ParseIntType::SignedAndUnsigned); break; - } - case 2: { - result = ParseInt64(s, end, Bitcast<uint64_t*>(lane_ptr), ParseIntType::SignedAndUnsigned); + case 2: + result = ParseInt64(s, end, reinterpret_cast<uint64_t*>(lane_ptr), + ParseIntType::SignedAndUnsigned); break; - } } } else { switch(lane_count) { - case 4: { - result = ParseFloat(literal.type, s, end, Bitcast<uint32_t*>(lane_ptr)); + case 4: + result = ParseFloat(literal.type, s, end, + reinterpret_cast<uint32_t*>(lane_ptr)); break; - } - case 2: { - result = ParseDouble(literal.type,s, end, Bitcast<uint64_t*>(lane_ptr)); + case 2: + result = ParseDouble(literal.type, s, end, + reinterpret_cast<uint64_t*>(lane_ptr)); break; - } } } |