Skip to content

Commit fc0e985

Browse files
WAT: Fix too large/too small float/integer parsing
1 parent 26715dd commit fc0e985

File tree

2 files changed

+28
-31
lines changed

2 files changed

+28
-31
lines changed

Sources/WAT/Parser.swift

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -80,25 +80,22 @@ internal struct Parser {
8080
}
8181
try consume()
8282
let value: UnsignedType
83+
let makeError = { [lexer] in
84+
WatParserError("invalid literal \(token.text(from: lexer))", location: token.location(in: lexer))
85+
}
8386
switch pattern {
8487
case .hexPattern(let pattern):
85-
guard let index = UnsignedType(pattern, radix: 16) else {
86-
throw WatParserError("invalid index \(pattern)", location: token.location(in: lexer))
87-
}
88+
guard let index = UnsignedType(pattern, radix: 16) else { throw makeError() }
8889
value = index
8990
case .decimalPattern(let pattern):
90-
guard let index = UnsignedType(pattern) else {
91-
throw WatParserError("invalid index \(pattern)", location: token.location(in: lexer))
92-
}
91+
guard let index = UnsignedType(pattern) else { throw makeError() }
9392
value = index
9493
}
9594
switch sign {
9695
case .plus, nil: return fromBitPattern(value)
9796
case .minus:
9897
let casted = fromBitPattern(~value &+ 1)
99-
guard casted <= 0 else {
100-
throw WatParserError("invalid literal \(token.text(from: lexer))", location: token.location(in: lexer))
101-
}
98+
guard casted <= 0 else { throw makeError() }
10299
return casted
103100
}
104101
}
@@ -185,7 +182,7 @@ internal struct Parser {
185182
}
186183

187184
mutating func expectFloatingPoint<F: BinaryFloatingPoint & LosslessStringConvertible, BitPattern: FixedWidthInteger>(
188-
_: F.Type, toBitPattern: (F) -> BitPattern,
185+
_: F.Type, toBitPattern: (F) -> BitPattern, isNaN: (BitPattern) -> Bool,
189186
buildBitPattern: (
190187
_ sign: FloatingPointSign,
191188
_ exponentBitPattern: UInt,
@@ -198,44 +195,43 @@ internal struct Parser {
198195
return 1 &<< UInt(F.exponentBitCount) - 1
199196
}
200197

198+
let makeError = { [lexer] in
199+
WatParserError("invalid float literal \(token.text(from: lexer))", location: token.location(in: lexer))
200+
}
201+
let parse = { (pattern: String) throws -> F in
202+
// Swift's Float{32,64} initializer returns +/- infinity for too large/too small values.
203+
// We know that the given pattern will not be expected to be parsed as infinity,
204+
// so we can check if the parsing succeeded by checking if the returned value is infinite.
205+
guard let value = F(pattern), !value.isInfinite else { throw makeError() }
206+
return value
207+
}
201208
switch token.kind {
202209
case let .float(sign, pattern):
203210
let float: F
204211
switch pattern {
205212
case .decimalPattern(let pattern):
206-
guard let value = F(pattern) else {
207-
throw WatParserError("invalid float \(pattern)", location: token.location(in: lexer))
208-
}
209-
float = value
213+
float = try parse(pattern)
210214
case .hexPattern(let pattern):
211-
guard let value = F("0x" + pattern) else {
212-
throw WatParserError("invalid float \(pattern)", location: token.location(in: lexer))
213-
}
214-
float = value
215+
float = try parse("0x" + pattern)
215216
case .inf:
216217
float = .infinity
217218
case .nan(hexPattern: nil):
218219
float = .nan
219220
case .nan(let hexPattern?):
220-
guard let bitPattern = BitPattern(hexPattern, radix: 16) else {
221-
throw WatParserError("invalid float \(hexPattern)", location: token.location(in: lexer))
222-
}
223-
return buildBitPattern(sign ?? .plus, infinityExponent, UInt(bitPattern))
221+
guard let significandBitPattern = BitPattern(hexPattern, radix: 16) else { throw makeError() }
222+
let bitPattern = buildBitPattern(sign ?? .plus, infinityExponent, UInt(significandBitPattern))
223+
// Ensure that the given bit pattern is a NaN.
224+
guard isNaN(bitPattern) else { throw makeError() }
225+
return bitPattern
224226
}
225227
return toBitPattern(sign == .minus ? -float : float)
226228
case let .integer(sign, pattern):
227229
let float: F
228230
switch pattern {
229231
case .hexPattern(let pattern):
230-
guard let value = F("0x" + pattern) else {
231-
throw WatParserError("invalid float \(pattern)", location: token.location(in: lexer))
232-
}
233-
float = value
232+
float = try parse("0x" + pattern)
234233
case .decimalPattern(let pattern):
235-
guard let value = F(pattern) else {
236-
throw WatParserError("invalid float \(pattern)", location: token.location(in: lexer))
237-
}
238-
float = value
234+
float = try parse(pattern)
239235
}
240236
return toBitPattern(sign == .minus ? -float : float)
241237
default:
@@ -246,6 +242,7 @@ internal struct Parser {
246242
mutating func expectFloat32() throws -> IEEE754.Float32 {
247243
let bitPattern = try expectFloatingPoint(
248244
Float32.self, toBitPattern: \.bitPattern,
245+
isNaN: { Float32(bitPattern: $0).isNaN },
249246
buildBitPattern: {
250247
UInt32(
251248
($0 == .minus ? 1 : 0) << (Float32.exponentBitCount + Float32.significandBitCount)
@@ -259,6 +256,7 @@ internal struct Parser {
259256
mutating func expectFloat64() throws -> IEEE754.Float64 {
260257
let bitPattern = try expectFloatingPoint(
261258
Float64.self, toBitPattern: \.bitPattern,
259+
isNaN: { Float64(bitPattern: $0).isNaN },
262260
buildBitPattern: {
263261
UInt64(
264262
($0 == .minus ? 1 : 0) << (Float64.exponentBitCount + Float64.significandBitCount)

Tests/WATTests/EncoderTests.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ class EncoderTests: XCTestCase {
107107

108108
var stats = CompatibilityTestStats()
109109
let excluded: [String] = [
110-
"const.wast",
111110
"float_literals.wast",
112111
"imports.wast",
113112
"int_literals.wast",

0 commit comments

Comments
 (0)