Skip to content

Commit 838de5c

Browse files
authored
[Parser] Replace Signedness with ternary Sign (WebAssembly#4698)
Previously we were tracking whether integer tokens were signed but we did not differentiate between positive and negative signs. Unfortunately, without differentiating them, there's no way to tell the difference between an in-bounds negative integer and a wildly out-of-bounds positive integer when trying to perform bounds checks for s32 tokens. Fix the problem by tracking not only whether there is a sign on an integer token, but also what the sign is.
1 parent 410b7c9 commit 838de5c

File tree

3 files changed

+65
-67
lines changed

3 files changed

+65
-67
lines changed

src/wasm/wat-lexer.cpp

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ std::optional<int> getHexDigit(char c) {
123123
// The result of lexing an integer token fragment.
124124
struct LexIntResult : LexResult {
125125
uint64_t n;
126-
Signedness signedness;
126+
Sign sign;
127127
};
128128

129129
// Lexing context that accumulates lexed input to produce an integer token
@@ -133,8 +133,7 @@ struct LexIntCtx : LexCtx {
133133

134134
private:
135135
uint64_t n = 0;
136-
Signedness signedness = Unsigned;
137-
bool negative = false;
136+
Sign sign = NoSign;
138137
bool overflow = false;
139138

140139
public:
@@ -143,42 +142,41 @@ struct LexIntCtx : LexCtx {
143142
// Lex only the underlying span, ignoring the overflow and value.
144143
std::optional<LexIntResult> lexedRaw() {
145144
if (auto basic = LexCtx::lexed()) {
146-
return LexIntResult{*basic, 0, Unsigned};
145+
return LexIntResult{*basic, 0, NoSign};
147146
}
148147
return {};
149148
}
150149

151150
std::optional<LexIntResult> lexed() {
152-
// Check most significant bit for overflow of signed numbers.
153151
if (overflow) {
154152
return {};
155153
}
156154
auto basic = LexCtx::lexed();
157155
if (!basic) {
158156
return {};
159157
}
160-
if (signedness == Signed) {
161-
if (negative) {
162-
if (n > (1ull << 63)) {
163-
// TODO: Add error production for signed underflow.
164-
return {};
165-
}
166-
} else {
167-
if (n > (1ull << 63) - 1) {
168-
// TODO: Add error production for signed overflow.
169-
return {};
170-
}
158+
// Check most significant bit for overflow of signed numbers.
159+
if (sign == Neg) {
160+
if (n > (1ull << 63)) {
161+
// TODO: Add error production for signed underflow.
162+
return {};
163+
}
164+
} else if (sign == Pos) {
165+
if (n > (1ull << 63) - 1) {
166+
// TODO: Add error production for signed overflow.
167+
return {};
171168
}
172169
}
173-
return LexIntResult{*basic, negative ? -n : n, signedness};
170+
return LexIntResult{*basic, sign == Neg ? -n : n, sign};
174171
}
175172

176173
void takeSign() {
177174
if (takePrefix("+"sv)) {
178-
signedness = Signed;
175+
sign = Pos;
179176
} else if (takePrefix("-"sv)) {
180-
signedness = Signed;
181-
negative = true;
177+
sign = Neg;
178+
} else {
179+
sign = NoSign;
182180
}
183181
}
184182

@@ -799,7 +797,7 @@ void Lexer::lexToken() {
799797
} else if (auto t = ident(next())) {
800798
tok = Token{t->span, IdTok{}};
801799
} else if (auto t = integer(next())) {
802-
tok = Token{t->span, IntTok{t->n, t->signedness}};
800+
tok = Token{t->span, IntTok{t->n, t->sign}};
803801
} else if (auto t = float_(next())) {
804802
tok = Token{t->span, FloatTok{t->nanPayload, t->d}};
805803
} else if (auto t = str(next())) {
@@ -834,7 +832,7 @@ bool TextPos::operator==(const TextPos& other) const {
834832
}
835833

836834
bool IntTok::operator==(const IntTok& other) const {
837-
return n == other.n && signedness == other.signedness;
835+
return n == other.n && sign == other.sign;
838836
}
839837

840838
bool FloatTok::operator==(const FloatTok& other) const {
@@ -872,7 +870,7 @@ std::ostream& operator<<(std::ostream& os, const RParenTok&) {
872870
std::ostream& operator<<(std::ostream& os, const IdTok&) { return os << "id"; }
873871

874872
std::ostream& operator<<(std::ostream& os, const IntTok& tok) {
875-
return os << tok.n << (tok.signedness == Signed ? " signed" : " unsigned");
873+
return os << (tok.sign == Pos ? "+" : tok.sign == Neg ? "-" : "") << tok.n;
876874
}
877875

878876
std::ostream& operator<<(std::ostream& os, const FloatTok& tok) {

src/wat-lexer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ struct IdTok {
5555
friend std::ostream& operator<<(std::ostream&, const IdTok&);
5656
};
5757

58-
enum Signedness { Unsigned, Signed };
58+
enum Sign { NoSign, Pos, Neg };
5959

6060
struct IntTok {
6161
uint64_t n;
62-
Signedness signedness;
62+
Sign sign;
6363

6464
bool operator==(const IntTok&) const;
6565
friend std::ostream& operator<<(std::ostream&, const IntTok&);

0 commit comments

Comments
 (0)