mirror of
https://github.com/mkxp-z/mkxp-z.git
synced 2025-09-10 03:52:55 +02:00
Prevent unaligned memory accesses in libretro builds
These are undefined behaviour. All memory accesses need to be aligned. For unaligned memory accesses, we have to use memcpy.
This commit is contained in:
parent
e3146c5e1d
commit
81cb43ef37
3 changed files with 90 additions and 53 deletions
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
@ -153,8 +155,18 @@ namespace mkxp_sandbox {
|
|||
// Gets a reference to the value stored at a given address in sandbox memory.
|
||||
template <typename T> T &sandbox_ref(struct w2c_ruby &instance, wasm_ptr_t address) noexcept {
|
||||
static_assert(std::is_arithmetic<T>::value, "can only get references to numeric values in the sandbox");
|
||||
if (address % sizeof(T) != 0) {
|
||||
#ifdef MKXPZ_RETRO_MEMORY64
|
||||
std::fprintf(stderr, "unaligned memory access of size %u at address 0x%016llx in `mkxp_sandbox::sandbox_ref()`\n", (unsigned int)sizeof(T), (unsigned long long)address);
|
||||
#else
|
||||
std::fprintf(stderr, "unaligned memory access of size %u at address 0x%08llx in `mkxp_sandbox::sandbox_ref()`\n", (unsigned int)sizeof(T), (unsigned long long)address);
|
||||
#endif // MKXPZ_RETRO_MEMORY64
|
||||
std::fflush(stderr);
|
||||
std::abort();
|
||||
}
|
||||
assert(address % sizeof(T) == 0);
|
||||
#ifdef MKXPZ_BIG_ENDIAN
|
||||
return *(T *)((uint8_t *)sandbox_ptr(instance, address) - sizeof(T));
|
||||
return *(T *)sandbox_ptr(instance, address + sizeof(T));
|
||||
#else
|
||||
return *(T *)sandbox_ptr(instance, address);
|
||||
#endif // MKXPZ_BIG_ENDIAN
|
||||
|
|
|
@ -178,64 +178,63 @@ bool sandbox_swizzle_info::get_exists() const {
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(bool value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint8_t));
|
||||
*(uint8_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(uint8_t));
|
||||
ADVANCE(sizeof(uint8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(bool &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint8_t));
|
||||
value = *(uint8_t *)data;
|
||||
std::memcpy(&value, data, sizeof(uint8_t));
|
||||
ADVANCE(sizeof(uint8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(int8_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int8_t));
|
||||
*(int8_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(int8_t));
|
||||
ADVANCE(sizeof(int8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(int8_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int8_t));
|
||||
value = *(int8_t *)data;
|
||||
std::memcpy(&value, data, sizeof(int8_t));
|
||||
ADVANCE(sizeof(int8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(uint8_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint8_t));
|
||||
*(uint8_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(uint8_t));
|
||||
ADVANCE(sizeof(uint8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(uint8_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint8_t));
|
||||
value = *(uint8_t *)data;
|
||||
std::memcpy(&value, data, sizeof(uint8_t));
|
||||
ADVANCE(sizeof(uint8_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(int16_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int16_t));
|
||||
*(int16_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(int16_t));
|
||||
ADVANCE(sizeof(int16_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(int16_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int16_t));
|
||||
std::memcpy(&value, data, sizeof(int16_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
static_assert(sizeof(unsigned short) == sizeof(int16_t), "unsigned short should be 16 bits");
|
||||
value = (int16_t)_byteswap_ushort(*(unsigned short *)data);
|
||||
value = (int16_t)_byteswap_ushort((unsigned short)value);
|
||||
#else
|
||||
value = (int16_t)__builtin_bswap16(*(uint16_t *)data);
|
||||
value = (int16_t)__builtin_bswap16((uint16_t)value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(int16_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(int16_t));
|
||||
return true;
|
||||
|
@ -243,22 +242,21 @@ template <> bool mkxp_sandbox::sandbox_deserialize(int16_t &value, const void *&
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(uint16_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint16_t));
|
||||
*(uint16_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(uint16_t));
|
||||
ADVANCE(sizeof(uint16_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(uint16_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint16_t));
|
||||
std::memcpy(&value, data, sizeof(uint16_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
static_assert(sizeof(unsigned short) == sizeof(uint16_t), "unsigned short should be 16 bits");
|
||||
value = (uint16_t)_byteswap_ushort(*(unsigned short *)data);
|
||||
value = (uint16_t)_byteswap_ushort((unsigned short)value);
|
||||
#else
|
||||
value = __builtin_bswap16(*(uint16_t *)data);
|
||||
value = __builtin_bswap16(value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(uint16_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(uint16_t));
|
||||
return true;
|
||||
|
@ -266,22 +264,21 @@ template <> bool mkxp_sandbox::sandbox_deserialize(uint16_t &value, const void *
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(int32_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int32_t));
|
||||
*(int32_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(int32_t));
|
||||
ADVANCE(sizeof(int32_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(int32_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int32_t));
|
||||
std::memcpy(&value, data, sizeof(int32_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
static_assert(sizeof(unsigned long) == sizeof(int32_t), "unsigned long should be 32 bits");
|
||||
value = (int32_t)_byteswap_ulong(*(unsigned long *)data);
|
||||
value = (int32_t)_byteswap_ulong((unsigned long)value);
|
||||
#else
|
||||
value = (int32_t)__builtin_bswap32(*(uint32_t *)data);
|
||||
value = (int32_t)__builtin_bswap32((uint32_t)value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(int32_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(int32_t));
|
||||
return true;
|
||||
|
@ -289,22 +286,21 @@ template <> bool mkxp_sandbox::sandbox_deserialize(int32_t &value, const void *&
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(uint32_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint32_t));
|
||||
*(uint32_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(uint32_t));
|
||||
ADVANCE(sizeof(uint32_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(uint32_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint32_t));
|
||||
std::memcpy(&value, data, sizeof(uint32_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
static_assert(sizeof(unsigned long) == sizeof(uint32_t), "unsigned long should be 32 bits");
|
||||
value = (uint32_t)_byteswap_ulong(*(unsigned long *)data);
|
||||
value = (uint32_t)_byteswap_ulong((unsigned long)value);
|
||||
#else
|
||||
value = __builtin_bswap32(*(uint32_t *)data);
|
||||
value = __builtin_bswap32(value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(uint32_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(uint32_t));
|
||||
return true;
|
||||
|
@ -312,21 +308,20 @@ template <> bool mkxp_sandbox::sandbox_deserialize(uint32_t &value, const void *
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(int64_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int64_t));
|
||||
*(int64_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(int64_t));
|
||||
ADVANCE(sizeof(int64_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(int64_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(int64_t));
|
||||
std::memcpy(&value, data, sizeof(int64_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
value = (int64_t)_byteswap_uint64(*(unsigned __int64 *)data);
|
||||
value = (int64_t)_byteswap_uint64((unsigned __int64)value);
|
||||
#else
|
||||
value = (int64_t)__builtin_bswap64(*(uint64_t *)data);
|
||||
value = (int64_t)__builtin_bswap64((uint64_t)value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(int64_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(int64_t));
|
||||
return true;
|
||||
|
@ -334,21 +329,20 @@ template <> bool mkxp_sandbox::sandbox_deserialize(int64_t &value, const void *&
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(uint64_t value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint64_t));
|
||||
*(uint64_t *)data = value;
|
||||
std::memcpy(data, &value, sizeof(uint64_t));
|
||||
ADVANCE(sizeof(uint64_t));
|
||||
return true;
|
||||
}
|
||||
|
||||
template <> bool mkxp_sandbox::sandbox_deserialize(uint64_t &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(uint64_t));
|
||||
std::memcpy(&value, data, sizeof(uint64_t));
|
||||
if (deser_swap_bytes) {
|
||||
#ifdef _MSC_VER
|
||||
value = (uint64_t)_byteswap_uint64(*(unsigned __int64 *)data);
|
||||
value = (uint64_t)_byteswap_uint64((unsigned __int64)value);
|
||||
#else
|
||||
value = __builtin_bswap64(*(uint64_t *)data);
|
||||
value = __builtin_bswap64(value);
|
||||
#endif // _MSC_VER
|
||||
} else {
|
||||
value = *(uint64_t *)data;
|
||||
}
|
||||
ADVANCE(sizeof(uint64_t));
|
||||
return true;
|
||||
|
@ -356,7 +350,7 @@ template <> bool mkxp_sandbox::sandbox_deserialize(uint64_t &value, const void *
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(float value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(float));
|
||||
*(float *)data = value;
|
||||
std::memcpy(data, &value, sizeof(float));
|
||||
ADVANCE(sizeof(float));
|
||||
return true;
|
||||
}
|
||||
|
@ -364,15 +358,17 @@ template <> bool mkxp_sandbox::sandbox_serialize(float value, void *&data, wasm_
|
|||
template <> bool mkxp_sandbox::sandbox_deserialize(float &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(float));
|
||||
if (deser_swap_bytes) {
|
||||
uint32_t tmp;
|
||||
std::memcpy(&tmp, data, sizeof(float));
|
||||
#ifdef _MSC_VER
|
||||
static_assert(sizeof(unsigned long) == sizeof(float), "unsigned long should be 32 bits");
|
||||
uint32_t tmp = (uint32_t)_byteswap_ulong(*(unsigned long *)data);
|
||||
tmp = (uint32_t)_byteswap_ulong((unsigned long)tmp);
|
||||
#else
|
||||
uint32_t tmp = __builtin_bswap32(*(uint32_t *)data);
|
||||
tmp = __builtin_bswap32(tmp);
|
||||
#endif // _MSC_VER
|
||||
std::memcpy(&value, &tmp, 4);
|
||||
std::memcpy(&value, &tmp, sizeof(float));
|
||||
} else {
|
||||
value = *(float *)data;
|
||||
std::memcpy(&value, data, sizeof(float));
|
||||
}
|
||||
ADVANCE(sizeof(float));
|
||||
return true;
|
||||
|
@ -380,7 +376,7 @@ template <> bool mkxp_sandbox::sandbox_deserialize(float &value, const void *&da
|
|||
|
||||
template <> bool mkxp_sandbox::sandbox_serialize(double value, void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(double));
|
||||
*(double *)data = value;
|
||||
std::memcpy(data, &value, sizeof(double));
|
||||
ADVANCE(sizeof(double));
|
||||
return true;
|
||||
}
|
||||
|
@ -388,14 +384,16 @@ template <> bool mkxp_sandbox::sandbox_serialize(double value, void *&data, wasm
|
|||
template <> bool mkxp_sandbox::sandbox_deserialize(double &value, const void *&data, wasm_size_t &max_size) {
|
||||
RESERVE(sizeof(double));
|
||||
if (deser_swap_bytes) {
|
||||
uint64_t tmp;
|
||||
std::memcpy(&tmp, data, sizeof(double));
|
||||
#ifdef _MSC_VER
|
||||
uint64_t tmp = (uint64_t)_byteswap_uint64(*(unsigned __int64 *)data);
|
||||
tmp = (uint64_t)_byteswap_uint64((unsigned __int64)tmp);
|
||||
#else
|
||||
uint64_t tmp = __builtin_bswap64(*(uint64_t *)data);
|
||||
tmp = __builtin_bswap64(tmp);
|
||||
#endif // _MSC_VER
|
||||
std::memcpy(&value, &tmp, 8);
|
||||
std::memcpy(&value, &tmp, sizeof(double));
|
||||
} else {
|
||||
value = *(double *)data;
|
||||
std::memcpy(&value, data, sizeof(double));
|
||||
}
|
||||
ADVANCE(sizeof(double));
|
||||
return true;
|
||||
|
|
|
@ -479,7 +479,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u
|
|||
return WASI_EIO;
|
||||
}
|
||||
wasi->ref<uint64_t>(result) = fd; // dev
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino // TODO: generate a pseudorandom inode number
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino
|
||||
wasi->ref<uint8_t>(result + 16) = WASI_IFDIR; // filetype
|
||||
wasi->ref<uint32_t>(result + 24) = 1; // nlink
|
||||
wasi->ref<uint64_t>(result + 32) = stat.filesize; // size
|
||||
|
@ -499,7 +499,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_filestat_get(wasi_t *wasi, u
|
|||
return WASI_EIO;
|
||||
}
|
||||
wasi->ref<uint64_t>(result) = fd; // dev
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino // TODO: generate a pseudorandom inode number
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino
|
||||
wasi->ref<uint8_t>(result + 16) = WASI_IFREG; // filetype
|
||||
wasi->ref<uint32_t>(result + 24) = 1; // nlink
|
||||
wasi->ref<uint64_t>(result + 32) = stat.filesize; // size
|
||||
|
@ -694,19 +694,46 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_readdir(wasi_t *wasi, uint32
|
|||
if (edata->buf - edata->original_buf + 8 > edata->buf_len) {
|
||||
return PHYSFS_ENUM_STOP;
|
||||
}
|
||||
wasi->ref<uint64_t>(edata->buf) = edata->cookie;
|
||||
std::memcpy(
|
||||
#ifdef MKXPZ_BIG_ENDIAN
|
||||
wasi->ptr(edata->buf + 8),
|
||||
#else
|
||||
wasi->ptr(edata->buf),
|
||||
#endif // MKXPZ_BIG_ENDIAN
|
||||
&edata->cookie,
|
||||
8
|
||||
);
|
||||
edata->buf += 8;
|
||||
|
||||
if (edata->buf - edata->original_buf + 8 > edata->buf_len) {
|
||||
return PHYSFS_ENUM_STOP;
|
||||
}
|
||||
wasi->ref<uint64_t>(edata->buf) = 0; // TODO: generate a pseudorandom inode number
|
||||
std::memset(
|
||||
#ifdef MKXPZ_BIG_ENDIAN
|
||||
wasi->ptr(edata->buf + 8),
|
||||
#else
|
||||
wasi->ptr(edata->buf),
|
||||
#endif // MKXPZ_BIG_ENDIAN
|
||||
0,
|
||||
8
|
||||
);
|
||||
edata->buf += 8;
|
||||
|
||||
if (edata->buf - edata->original_buf + 4 > edata->buf_len) {
|
||||
return PHYSFS_ENUM_STOP;
|
||||
}
|
||||
wasi->ref<uint32_t>(edata->buf) = std::strlen(filename);
|
||||
{
|
||||
const uint32_t value = std::strlen(filename);
|
||||
std::memcpy(
|
||||
#ifdef MKXPZ_BIG_ENDIAN
|
||||
wasi->ptr(edata->buf + 8),
|
||||
#else
|
||||
wasi->ptr(edata->buf),
|
||||
#endif // MKXPZ_BIG_ENDIAN
|
||||
&value,
|
||||
4
|
||||
);
|
||||
}
|
||||
edata->buf += 4;
|
||||
|
||||
if (edata->buf - edata->original_buf + 4 > edata->buf_len) {
|
||||
|
@ -948,7 +975,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_path_filestat_get(wasi_t *wasi,
|
|||
}
|
||||
|
||||
wasi->ref<uint64_t>(result) = fd; // dev
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino // TODO: generate a pseudorandom inode number
|
||||
wasi->ref<uint64_t>(result + 8) = 0; // ino
|
||||
wasi->ref<uint8_t>(result + 16) = stat.filetype == PHYSFS_FILETYPE_DIRECTORY ? WASI_IFDIR : WASI_IFREG; // filetype
|
||||
wasi->ref<uint32_t>(result + 24) = 1; // nlink
|
||||
wasi->ref<uint64_t>(result + 32) = stat.filetype; // size
|
||||
|
|
Loading…
Add table
Reference in a new issue