summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJF Bastien <github@jfbastien.com>2016-05-02 18:03:16 -0700
committerJF Bastien <github@jfbastien.com>2016-05-02 18:03:16 -0700
commit757084eec25159a1f34a1a6fde7754dee18ac8b9 (patch)
tree65067f8f3c2ec454b3b135ddff3cd273dc3157d1
parent5456ae59515d08c1c3de3aaca7331d420ede8a32 (diff)
downloadbinaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.tar.gz
binaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.tar.bz2
binaryen-757084eec25159a1f34a1a6fde7754dee18ac8b9.zip
Fix UB with FP divide by zero (#424)
Another fix for #404.
-rw-r--r--src/wasm.h42
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();
}
}