diff options
author | JF Bastien <github@jfbastien.com> | 2016-05-02 18:03:16 -0700 |
---|---|---|
committer | JF Bastien <github@jfbastien.com> | 2016-05-02 18:03:16 -0700 |
commit | 757084eec25159a1f34a1a6fde7754dee18ac8b9 (patch) | |
tree | 65067f8f3c2ec454b3b135ddff3cd273dc3157d1 /src | |
parent | 5456ae59515d08c1c3de3aaca7331d420ede8a32 (diff) | |
download | binaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.tar.gz binaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.tar.bz2 binaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.zip |
Fix UB with FP divide by zero (#424)
Another fix for #404.
Diffstat (limited to 'src')
-rw-r--r-- | src/wasm.h | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/src/wasm.h b/src/wasm.h index 393f0529b..dcad171a0 100644 --- a/src/wasm.h +++ b/src/wasm.h @@ -436,8 +436,46 @@ public: } Literal div(const Literal& other) const { switch (type) { - case WasmType::f32: return Literal(getf32() / other.getf32()); - case WasmType::f64: return Literal(getf64() / other.getf64()); + case WasmType::f32: { + float lhs = getf32(), rhs = other.getf32(); + float sign = std::signbit(lhs) == std::signbit(rhs) ? 0.f : -0.f; + switch (std::fpclassify(rhs)) { + case FP_ZERO: + switch (std::fpclassify(lhs)) { + case FP_NAN: return *this; + case FP_ZERO: return Literal(std::copysign(std::numeric_limits<float>::quiet_NaN(), sign)); + case FP_NORMAL: // fallthrough + case FP_SUBNORMAL: // fallthrough + case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<float>::infinity(), sign)); + default: WASM_UNREACHABLE(); + } + case FP_NAN: // fallthrough + case FP_INFINITE: // fallthrough + case FP_NORMAL: // fallthrough + case FP_SUBNORMAL: return Literal(lhs / rhs); + default: WASM_UNREACHABLE(); + } + } + case WasmType::f64: { + double lhs = getf64(), rhs = other.getf64(); + double sign = std::signbit(lhs) == std::signbit(rhs) ? 0. : -0.; + switch (std::fpclassify(rhs)) { + case FP_ZERO: + switch (std::fpclassify(lhs)) { + case FP_NAN: return *this; + case FP_ZERO: return Literal(std::copysign(std::numeric_limits<double>::quiet_NaN(), sign)); + case FP_NORMAL: // fallthrough + case FP_SUBNORMAL: // fallthrough + case FP_INFINITE: return Literal(std::copysign(std::numeric_limits<double>::infinity(), sign)); + default: WASM_UNREACHABLE(); + } + case FP_NAN: // fallthrough + case FP_INFINITE: // fallthrough + case FP_NORMAL: // fallthrough + case FP_SUBNORMAL: return Literal(lhs / rhs); + default: WASM_UNREACHABLE(); + } + } default: WASM_UNREACHABLE(); } } |