Merge pull request #427 from WebAssembly/c-api-nice

C API
diff --git a/.travis.yml b/.travis.yml
index 7c69a5d..61585c3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,7 +13,7 @@
           sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']
           packages: ['cmake', 'nodejs', 'clang-3.6']
 
-    - env: COMPILER_VERSION=3.6 COMPILER_FLAGS="-fsanitize=undefined -fsanitize-blacklist=`pwd`/ubsan.blacklist"
+    - env: COMPILER_VERSION=3.6 COMPILER_FLAGS="-fsanitize=undefined -fno-sanitize-recover=all -fsanitize-blacklist=`pwd`/ubsan.blacklist"
       compiler: clang
       addons: *clang36
 
diff --git a/src/s2wasm.h b/src/s2wasm.h
index 3efd667..56d96dd 100644
--- a/src/s2wasm.h
+++ b/src/s2wasm.h
@@ -207,7 +207,8 @@
   // returns whether this is a relocation
   bool getConst(uint32_t* target) {
     if (isdigit(*s) || *s == '-') {
-      *target = getInt();
+      int32_t val = getInt();
+      memcpy(target, &val, sizeof(val));
       return false;
     } else {
       // a global constant, we need to fix it up later
@@ -1073,7 +1074,8 @@
       } else if (match(".int16")) {
         size_t size = raw.size();
         raw.resize(size + 2);
-        (*(int16_t*)(&raw[size])) = getInt();
+        int16_t val = getInt();
+        memcpy(&raw[size], &val, sizeof(val));
         zero = false;
       } else if (match(".int32")) {
         size_t size = raw.size();
@@ -1085,7 +1087,8 @@
       } else if (match(".int64")) {
         size_t size = raw.size();
         raw.resize(size + 8);
-        (*(int64_t*)(&raw[size])) = getInt64();
+        int64_t val = getInt64();
+        memcpy(&raw[size], &val, sizeof(val));
         zero = false;
       } else {
         break;
diff --git a/src/support/bits.cpp b/src/support/bits.cpp
index 3d03b10..aa72201 100644
--- a/src/support/bits.cpp
+++ b/src/support/bits.cpp
@@ -68,7 +68,7 @@
     0,   1, 28,  2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17,  4, 8,
     31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18,  6, 11,  5, 10, 9
   };
-  return v ? (int)tbl[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27] : 32;
+  return v ? (int)tbl[((uint32_t)((v & -v) * 0x077CB531U)) >> 27] : 32;
 }
 
 template<>
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index d0e64c9..5e30112 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -455,7 +455,14 @@
             case TruncSFloat64:    return truncSFloat(curr, value);
             case TruncUFloat64:    return truncUFloat(curr, value);
             case ReinterpretFloat: return value.castToI64();
-            case DemoteFloat64:    return value.truncateToF32();
+            case DemoteFloat64: {
+              double val = value.getFloat();
+              if (std::isnan(val)) return Literal(float(val));
+              if (std::isinf(val)) return Literal(float(val));
+              if (val < -std::numeric_limits<float>::max()) return Literal(-std::numeric_limits<float>::infinity());
+              if (val > std::numeric_limits<float>::max()) return Literal(std::numeric_limits<float>::infinity());
+              return value.truncateToF32();
+            }
             default: abort();
           }
         }
diff --git a/src/wasm-s-parser.h b/src/wasm-s-parser.h
index 05715f7..af50a68 100644
--- a/src/wasm-s-parser.h
+++ b/src/wasm-s-parser.h
@@ -1067,42 +1067,46 @@
       Element& curr = *s[i];
       assert(curr[0]->str() == SEGMENT);
       const char *input = curr[2]->c_str();
-      std::vector<char> data;
-      data.resize(strlen(input));
-      char *write = (char*)&data[0];
-      while (1) {
-        if (input[0] == 0) break;
-        if (input[0] == '\\') {
-          if (input[1] == '"') {
-            *write++ = '"';
-            input += 2;
-            continue;
-          } else if (input[1] == '\'') {
-            *write++ = '\'';
-            input += 2;
-            continue;
-          } else if (input[1] == '\\') {
-            *write++ = '\\';
-            input += 2;
-            continue;
-          } else if (input[1] == 'n') {
-            *write++ = '\n';
-            input += 2;
-            continue;
-          } else if (input[1] == 't') {
-            *write++ = '\t';
-            input += 2;
-            continue;
-          } else {
-            *write++ = (char)(unhex(input[1])*16 + unhex(input[2]));
-            input += 3;
-            continue;
+      if (auto size = strlen(input)) {
+        std::vector<char> data;
+        data.resize(size);
+        char *write = data.data();
+        while (1) {
+          if (input[0] == 0) break;
+          if (input[0] == '\\') {
+            if (input[1] == '"') {
+              *write++ = '"';
+              input += 2;
+              continue;
+            } else if (input[1] == '\'') {
+              *write++ = '\'';
+              input += 2;
+              continue;
+            } else if (input[1] == '\\') {
+              *write++ = '\\';
+              input += 2;
+              continue;
+            } else if (input[1] == 'n') {
+              *write++ = '\n';
+              input += 2;
+              continue;
+            } else if (input[1] == 't') {
+              *write++ = '\t';
+              input += 2;
+              continue;
+            } else {
+              *write++ = (char)(unhex(input[1])*16 + unhex(input[2]));
+              input += 3;
+              continue;
+            }
           }
+          *write++ = input[0];
+          input++;
         }
-        *write++ = input[0];
-        input++;
+        wasm.memory.segments.emplace_back(atoi(curr[1]->c_str()), data.data(), write - data.data());
+      } else {
+        wasm.memory.segments.emplace_back(atoi(curr[1]->c_str()), "", 0);
       }
-      wasm.memory.segments.emplace_back(atoi(curr[1]->c_str()), (const char*)&data[0], write - (const char*)&data[0]);
       i++;
     }
   }
diff --git a/src/wasm.h b/src/wasm.h
index d61c8e5..e3c8ea7 100644
--- a/src/wasm.h
+++ b/src/wasm.h
@@ -409,8 +409,8 @@
 
   Literal add(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(i32 + other.i32);
-      case WasmType::i64: return Literal(i64 + other.i64);
+      case WasmType::i32: return Literal(uint32_t(i32) + uint32_t(other.i32));
+      case WasmType::i64: return Literal(uint64_t(i64) + uint64_t(other.i64));
       case WasmType::f32: return Literal(getf32() + other.getf32());
       case WasmType::f64: return Literal(getf64() + other.getf64());
       default: WASM_UNREACHABLE();
@@ -418,8 +418,8 @@
   }
   Literal sub(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(i32 - other.i32);
-      case WasmType::i64: return Literal(i64 - other.i64);
+      case WasmType::i32: return Literal(uint32_t(i32) - uint32_t(other.i32));
+      case WasmType::i64: return Literal(uint64_t(i64) - uint64_t(other.i64));
       case WasmType::f32: return Literal(getf32() - other.getf32());
       case WasmType::f64: return Literal(getf64() - other.getf64());
       default: WASM_UNREACHABLE();
@@ -427,8 +427,8 @@
   }
   Literal mul(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(i32 * other.i32);
-      case WasmType::i64: return Literal(i64 * other.i64);
+      case WasmType::i32: return Literal(uint32_t(i32) * uint32_t(other.i32));
+      case WasmType::i64: return Literal(uint64_t(i64) * uint64_t(other.i64));
       case WasmType::f32: return Literal(getf32() * other.getf32());
       case WasmType::f64: return Literal(getf64() * other.getf64());
       default: WASM_UNREACHABLE();
@@ -436,8 +436,46 @@
   }
   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();
     }
   }
@@ -492,22 +530,22 @@
   }
   Literal shl(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(i32 << other.i32);
-      case WasmType::i64: return Literal(i64 << other.i64);
+      case WasmType::i32: return Literal(uint32_t(i32) << (other.i32 & 0x1f));
+      case WasmType::i64: return Literal(uint64_t(i64) << (other.i64 & 0x3f));
       default: WASM_UNREACHABLE();
     }
   }
   Literal shrS(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(i32 >> other.i32);
-      case WasmType::i64: return Literal(i64 >> other.i64);
+      case WasmType::i32: return Literal(i32 >> (other.i32 & 0x1f));
+      case WasmType::i64: return Literal(i64 >> (other.i64 & 0x3f));
       default: WASM_UNREACHABLE();
     }
   }
   Literal shrU(const Literal& other) const {
     switch (type) {
-      case WasmType::i32: return Literal(uint32_t(i32) >> uint32_t(other.i32));
-      case WasmType::i64: return Literal(uint64_t(i64) >> uint64_t(other.i64));
+      case WasmType::i32: return Literal(uint32_t(i32) >> uint32_t(other.i32 & 0x1f));
+      case WasmType::i64: return Literal(uint64_t(i64) >> uint64_t(other.i64 & 0x3f));
       default: WASM_UNREACHABLE();
     }
   }
@@ -1188,7 +1226,7 @@
     Segment() {}
     Segment(size_t offset, const char *init, size_t size) : offset(offset) {
       data.resize(size);
-      memcpy(&data[0], init, size);
+      std::copy_n(init, size, data.begin());
     }
     Segment(size_t offset, std::vector<char>& init) : offset(offset) {
       data.swap(init);