Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,8 @@ template<> struct hash<wasm::Literal> {
return digest;
case wasm::Type::v128:
uint64_t chunks[2];
memcpy(&chunks, a.getv128Ptr(), 16);
chunks[0] = wasm::readLE<uint64_t>(a.getv128Ptr());
chunks[1] = wasm::readLE<uint64_t>(&a.getv128Ptr()[8]);
wasm::rehash(digest, chunks[0]);
wasm::rehash(digest, chunks[1]);
return digest;
Expand Down
25 changes: 2 additions & 23 deletions src/shell-interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,9 @@
namespace wasm {

struct ShellExternalInterface : ModuleRunner::ExternalInterface {
// The underlying memory can be accessed through unaligned pointers which
// isn't well-behaved in C++. WebAssembly nonetheless expects it to behave
// properly. Avoid emitting unaligned load/store by checking for alignment
// explicitly, and performing memcpy if unaligned.
//
// The allocated memory tries to have the same alignment as the memory being
// simulated.
class Memory {
// Use char because it doesn't run afoul of aliasing rules.
std::vector<char> memory;
template<typename T> static bool aligned(const char* address) {
static_assert(!(sizeof(T) & (sizeof(T) - 1)), "must be a power of 2");
return 0 == (reinterpret_cast<uintptr_t>(address) & (sizeof(T) - 1));
}

public:
Memory() = default;
Expand All @@ -65,20 +54,10 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface {
}
}
template<typename T> void set(size_t address, T value) {
if (aligned<T>(&memory[address])) {
*reinterpret_cast<T*>(&memory[address]) = value;
} else {
std::memcpy(&memory[address], &value, sizeof(T));
}
writeLE<T>(value, &memory[address]);
}
template<typename T> T get(size_t address) {
if (aligned<T>(&memory[address])) {
return *reinterpret_cast<T*>(&memory[address]);
} else {
T loaded;
std::memcpy(&loaded, &memory[address], sizeof(T));
return loaded;
}
return readLE<T>(&memory[address]);
}
};

Expand Down
38 changes: 38 additions & 0 deletions src/support/utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "compiler-support.h"

#include <cassert>
#include <climits>
#include <cstdint>
#include <cstring>
#include <iostream>
Expand Down Expand Up @@ -103,6 +104,43 @@ class Fatal {
#define WASM_UNREACHABLE(msg) wasm::handle_unreachable()
#endif

template<typename T, typename std::enable_if<std::is_same<T, typename std::array<uint8_t, std::tuple_size<T>::value>>::value, bool>::type = true>
void writeLE(T val, void *ptr) {
memcpy(ptr, val.data(), sizeof(T));
}

template<typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
void writeLE(T val, void *ptr) {
auto v = typename std::conditional<std::is_signed<T>::value, typename std::make_unsigned<T>::type, T>::type(val);
unsigned char *buf = reinterpret_cast<unsigned char *>(ptr);
#pragma GCC unroll 10
for (size_t i = 0; i < sizeof(T); ++i) {
buf[i] = v;
v >>= CHAR_BIT * (sizeof(T) != 1);
}
}

template<typename T, typename std::enable_if<std::is_same<T, typename std::array<uint8_t, std::tuple_size<T>::value>>::value, bool>::type = true>
T readLE(const void *ptr) {
T v;
memcpy(v.data(), ptr, sizeof(T));
return v;
}

template<typename T, typename std::enable_if<std::is_integral<T>::value, bool>::type = true>
T readLE(const void *ptr) {
auto v = typename std::conditional<std::is_signed<T>::value, typename std::make_unsigned<T>::type, T>::type(0);
const unsigned char *buf = reinterpret_cast<const unsigned char *>(ptr);
size_t i = sizeof(T);
#pragma GCC unroll 10
do {
--i;
v <<= CHAR_BIT * (sizeof(T) != 1);
v += buf[i];
} while (i);
return v;
}

} // namespace wasm

#endif // wasm_support_utilities_h
9 changes: 3 additions & 6 deletions src/tools/wasm-ctor-eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "support/insert_ordered.h"
#include "support/string.h"
#include "support/topological_sort.h"
#include "support/utilities.h"
#include "tool-options.h"
#include "wasm-builder.h"
#include "wasm-interpreter.h"
Expand Down Expand Up @@ -497,15 +498,11 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
}

template<typename T> void doStore(Address address, T value, Name memoryName) {
// Use memcpy to avoid UB if unaligned.
memcpy(getMemory(address, memoryName, sizeof(T)), &value, sizeof(T));
writeLE<T>(value, getMemory(address, memoryName, sizeof(T)));
}

template<typename T> T doLoad(Address address, Name memoryName) {
// Use memcpy to avoid UB if unaligned.
T ret;
memcpy(&ret, getMemory(address, memoryName, sizeof(T)), sizeof(T));
return ret;
return readLE<T>(getMemory(address, memoryName, sizeof(T)));
}

// Clear the state of the operation of applying the interpreter's runtime
Expand Down
5 changes: 3 additions & 2 deletions src/tools/wasm-fuzz-lattices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "analysis/transfer-function.h"

#include "support/command-line.h"
#include "support/utilities.h"
#include "tools/fuzzing.h"
#include "tools/fuzzing/random.h"

Expand Down Expand Up @@ -995,7 +996,7 @@ struct Fuzzer {
// Fewer bytes are needed to generate three random lattices.
std::vector<char> funcBytes(128);
for (size_t i = 0; i < funcBytes.size(); i += sizeof(uint64_t)) {
*(uint64_t*)(funcBytes.data() + i) = getFuncRand();
writeLE<uint64_t>(getFuncRand(), funcBytes.data() + i);
}

Random rand(std::move(funcBytes));
Expand Down Expand Up @@ -1030,7 +1031,7 @@ struct Fuzzer {
// 4kb of random bytes should be enough for anyone!
std::vector<char> bytes(4096);
for (size_t i = 0; i < bytes.size(); i += sizeof(uint64_t)) {
*(uint64_t*)(bytes.data() + i) = getRand();
writeLE<uint64_t>(getRand(), bytes.data() + i);
}

Module testModule;
Expand Down
3 changes: 2 additions & 1 deletion src/tools/wasm-fuzz-types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <variant>

#include "support/command-line.h"
#include "support/utilities.h"
#include "tools/fuzzing/heap-types.h"
#include "tools/fuzzing/random.h"
#include "wasm-type-printing.h"
Expand Down Expand Up @@ -68,7 +69,7 @@ void Fuzzer::run(uint64_t seed) {
// 4kb of random bytes should be enough for anyone!
std::vector<char> bytes(4096);
for (size_t i = 0; i < bytes.size(); i += sizeof(uint64_t)) {
*(uint64_t*)(bytes.data() + i) = getRand();
writeLE<uint64_t>(getRand(), bytes.data() + i);
}
rand = Random(std::move(bytes));

Expand Down
9 changes: 3 additions & 6 deletions src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "support/safe_integer.h"
#include "support/stdckdint.h"
#include "support/string.h"
#include "support/utilities.h"
#include "wasm-builder.h"
#include "wasm-limits.h"
#include "wasm-traversal.h"
Expand Down Expand Up @@ -2777,14 +2778,10 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
case Field::NotPacked:
return Literal::makeFromMemory(p, field.type);
case Field::i8: {
int8_t i;
memcpy(&i, p, sizeof(i));
return truncateForPacking(Literal(int32_t(i)), field);
return truncateForPacking(Literal(int32_t(readLE<int8_t>(p))), field);
}
case Field::i16: {
int16_t i;
memcpy(&i, p, sizeof(i));
return truncateForPacking(Literal(int32_t(i)), field);
return truncateForPacking(Literal(int32_t(readLE<int16_t>(p))), field);
}
case Field::WaitQueue: {
WASM_UNREACHABLE("waitqueue not implemented");
Expand Down
23 changes: 7 additions & 16 deletions src/wasm/literal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,7 @@ static void extractBytes(uint8_t (&dest)[16], const LaneArray<Lanes>& lanes) {
for (size_t lane_index = 0; lane_index < Lanes; ++lane_index) {
uint8_t bits[16];
lanes[lane_index].getBits(bits);
LaneT lane;
memcpy(&lane, bits, sizeof(lane));
LaneT lane = readLE<LaneT>(bits);
for (size_t offset = 0; offset < lane_width; ++offset) {
bytes.at(lane_index * lane_width + offset) =
uint8_t(lane >> (8 * offset));
Expand Down Expand Up @@ -316,24 +315,16 @@ Literal Literal::makeFromMemory(void* p, Type type) {
assert(type.isNumber());
switch (type.getBasic()) {
case Type::i32: {
int32_t i;
memcpy(&i, p, sizeof(i));
return Literal(i);
return Literal(readLE<int32_t>(p));
}
case Type::i64: {
int64_t i;
memcpy(&i, p, sizeof(i));
return Literal(i);
return Literal(readLE<int64_t>(p));
}
case Type::f32: {
int32_t i;
memcpy(&i, p, sizeof(i));
return Literal(bit_cast<float>(i));
return Literal(bit_cast<float>(readLE<int32_t>(p)));
}
case Type::f64: {
int64_t i;
memcpy(&i, p, sizeof(i));
return Literal(bit_cast<double>(i));
return Literal(bit_cast<double>(readLE<int64_t>(p)));
}
case Type::v128: {
uint8_t bytes[16];
Expand Down Expand Up @@ -460,11 +451,11 @@ void Literal::getBits(uint8_t (&buf)[16]) const {
switch (type.getBasic()) {
case Type::i32:
case Type::f32:
memcpy(buf, &i32, sizeof(i32));
writeLE<int32_t>(i32, buf);
break;
case Type::i64:
case Type::f64:
memcpy(buf, &i64, sizeof(i64));
writeLE<int64_t>(i64, buf);
break;
case Type::v128:
memcpy(buf, &v128, sizeof(v128));
Expand Down