Fix some bugs and safety issues in sandbox memory manipulation functions

This commit is contained in:
刘皓 2025-07-03 22:04:29 -04:00
parent cfaba64211
commit e22b2c6d5a
No known key found for this signature in database
GPG key ID: 7901753DB465B711
9 changed files with 136 additions and 189 deletions

View file

@ -122,28 +122,24 @@ void binding_base::copy_memory_from(const void *ptr, wasm_size_t size, wasm_size
}
}
void *mkxp_sandbox::sandbox_ptr(struct w2c_ruby &instance, wasm_ptr_t address) noexcept {
if (address >= instance.w2c_memory.size) {
std::abort();
}
#ifdef MKXPZ_BIG_ENDIAN
return instance.w2c_memory.data + instance.w2c_memory.size - address;
#else
return instance.w2c_memory.data + address;
#endif // MKXPZ_BIG_ENDIAN
}
wasm_size_t mkxp_sandbox::sandbox_strlen(struct w2c_ruby &instance, wasm_ptr_t address) noexcept {
const char *ptr = (char *)sandbox_ptr(instance, address);
const char *ptr = &sandbox_ref<char>(instance, address);
#ifdef MKXPZ_BIG_ENDIAN
wasm_size_t size = 0;
while ((uint8_t *)ptr != instance.w2c_memory.data && *--ptr) {
while (*ptr) {
if ((uint8_t *)ptr == instance.w2c_memory.data) {
std::abort();
}
++size;
--ptr;
}
return size;
#else
const char *end = (const char *)std::memchr(ptr, 0, instance.w2c_memory.size - address);
return ptr == nullptr ? instance.w2c_memory.size - address : end - ptr;
if (ptr == nullptr) {
std::abort();
}
return end - ptr;
#endif
}
@ -151,62 +147,24 @@ struct sandbox_str_guard mkxp_sandbox::sandbox_str(struct w2c_ruby &instance, wa
#ifdef MKXPZ_BIG_ENDIAN
std::string str;
str.reserve(sandbox_strlen(instance, address));
const char *ptr = (const char *)sandbox_ptr(instance, address);
while ((uint8_t *)ptr != instance.w2c_memory.data && *--ptr) {
for (const char *ptr = &sandbox_ref<char>(instance, address); *ptr; --ptr) {
str.push_back(*ptr);
}
return str;
#else
if (instance.w2c_memory.size - address <= sandbox_strlen(instance, address)) {
if (address >= instance.w2c_memory.size || instance.w2c_memory.size - address <= sandbox_strlen(instance, address)) {
std::abort();
}
return (const char *)sandbox_ptr(instance, address);
return &sandbox_ref<char>(instance, address);
#endif // MKXPZ_BIG_ENDIAN
}
void mkxp_sandbox::sandbox_strcpy(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src) noexcept {
#ifdef MKXPZ_BIG_ENDIAN
char *dst = (char *)sandbox_ptr(instance, dst_address);
while (*src) {
if ((uint8_t *)dst == instance.w2c_memory.data) {
std::abort();
}
*--dst = *src++;
}
*dst = 0;
#else
if (instance.w2c_memory.size - dst_address <= std::strlen(src)) {
std::abort();
}
char *dst = (char *)sandbox_ptr(instance, dst_address);
std::strcpy(dst, src);
#endif
sandbox_arycpy(instance, dst_address, src, (wasm_size_t)std::strlen(src) + 1);
}
void mkxp_sandbox::sandbox_strncpy(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) noexcept {
#ifdef MKXPZ_BIG_ENDIAN
char *dst = (char *)sandbox_ptr(instance, dst_address);
while (max_size && *src) {
if ((uint8_t *)dst == instance.w2c_memory.data) {
std::abort();
}
*--dst = *src++;
--max_size;
}
if (max_size) {
*dst = 0;
}
#else
if (instance.w2c_memory.size - dst_address <= std::strlen(src)) {
std::abort();
}
char *dst = (char *)sandbox_ptr(instance, dst_address);
std::strncpy(dst, src, max_size);
#endif
}
void *binding_base::ptr(wasm_ptr_t address) const noexcept {
return sandbox_ptr(instance(), address);
void mkxp_sandbox::sandbox_strncpy_s(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) noexcept {
sandbox_arycpy(instance, dst_address, src, std::min((wasm_size_t)std::strlen(src) + 1, max_size));
}
wasm_size_t binding_base::strlen(wasm_ptr_t address) const noexcept {
@ -221,8 +179,8 @@ void binding_base::strcpy(wasm_ptr_t dst_address, const char *src) const noexcep
sandbox_strcpy(instance(), dst_address, src);
}
void binding_base::strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept {
sandbox_strncpy(instance(), dst_address, src, max_size);
void binding_base::strncpy_s(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept {
sandbox_strncpy_s(instance(), dst_address, src, max_size);
}
binding_base::object::object() : ptr(nullptr), typenum(0) {}

View file

@ -151,11 +151,31 @@ namespace mkxp_sandbox {
};
// Gets a pointer to the given address in sandbox memory.
void *sandbox_ptr(struct w2c_ruby &instance, wasm_ptr_t address) noexcept;
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *sandbox_ptr_unaligned(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 + (wasm_ptr_t)sizeof(T) < address || address + (wasm_ptr_t)sizeof(T) > instance.w2c_memory.size) {
std::abort();
}
#ifdef MKXPZ_BIG_ENDIAN
return instance.w2c_memory.data + instance.w2c_memory.size - address - sizeof(T);
#else
return instance.w2c_memory.data + address;
#endif // MKXPZ_BIG_ENDIAN
}
// Gets a pointer to the given index in the array at a given address in sandbox memory.
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *sandbox_ptr_unaligned(struct w2c_ruby &instance, wasm_ptr_t array_address, wasm_size_t array_index) noexcept {
if (array_address + array_index < array_address) {
std::abort();
}
return sandbox_ptr_unaligned<T>(instance, array_address + array_index * sizeof(T));
}
// Gets a reference to the value stored at a given address in sandbox memory.
// Make sure the address is aligned, or this function will abort.
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);
@ -165,16 +185,14 @@ namespace mkxp_sandbox {
std::fflush(stderr);
std::abort();
}
assert(address % sizeof(T) == 0);
#ifdef MKXPZ_BIG_ENDIAN
return *(T *)sandbox_ptr(instance, address + sizeof(T));
#else
return *(T *)sandbox_ptr(instance, address);
#endif // MKXPZ_BIG_ENDIAN
return *(T *)sandbox_ptr_unaligned<T>(instance, address);
}
// Gets a reference to the value stored at the given index in the array at a given address in sandbox memory.
template <typename T> T &sandbox_ref(struct w2c_ruby &instance, wasm_ptr_t array_address, wasm_size_t array_index) noexcept {
if (array_address + array_index < array_address) {
std::abort();
}
return sandbox_ref<T>(array_address + array_index * sizeof(T));
}
@ -218,26 +236,20 @@ namespace mkxp_sandbox {
void sandbox_strcpy(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src) noexcept;
// Copies a string into a sandbox memory address.
void sandbox_strncpy(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) noexcept;
void sandbox_strncpy_s(struct w2c_ruby &instance, wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) noexcept;
// Copies an array of length `num_elements` into a sandbox memory address.
template <typename T> void sandbox_arycpy(struct w2c_ruby &instance, wasm_ptr_t dst_address, const T *src, wasm_size_t num_elements) noexcept {
#ifdef MKXPZ_BIG_ENDIAN
T *dst = (T *)sandbox_ptr(instance, dst_address);
while (num_elements > 0) {
if ((uint8_t *)dst - instance.w2c_memory.data < sizeof(T)) {
std::abort();
}
*--dst = *src++;
--num_elements;
}
#else
if (instance.w2c_memory.size - dst_address < num_elements * sizeof(T)) {
if (dst_address >= instance.w2c_memory.size || instance.w2c_memory.size - dst_address < num_elements * sizeof(T)) {
std::abort();
}
T *dst = (T *)sandbox_ptr(instance, dst_address);
#ifdef MKXPZ_BIG_ENDIAN
for (wasm_size_t i = 0; i < num_elements; ++i) {
std::memcpy(sandbox_ptr_unaligned<T>(instance, dst_address, i), src + i, sizeof(T));
}
#else
if (num_elements > 0) {
std::memcpy(dst, src, num_elements * sizeof(T));
std::memcpy(sandbox_ptr_unaligned<T>(instance, dst_address), src, num_elements * sizeof(T));
}
#endif
}
@ -351,14 +363,25 @@ namespace mkxp_sandbox {
void copy_memory_from(const void *ptr, wasm_size_t size, wasm_size_t capacity, bool swap_bytes) noexcept;
// Gets a pointer to the given address in sandbox memory.
void *ptr(wasm_ptr_t address) const noexcept;
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *ptr_unaligned(wasm_ptr_t address) const noexcept {
return sandbox_ptr_unaligned<T>(instance(), address);
}
// Gets a pointer to the given index in the array at a given address in sandbox memory.
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *ptr_unaligned(wasm_ptr_t array_address, wasm_size_t array_index) const noexcept {
return sandbox_ptr_unaligned<T>(instance(), array_address, array_index);
}
// Gets a reference to the value stored at a given address in sandbox memory.
// Make sure the address is aligned, or this function will abort.
template <typename T> T &ref(wasm_ptr_t address) const noexcept {
return sandbox_ref<T>(instance(), address);
}
// Gets a reference to the value stored at the given index in the array at a given address in sandbox memory.
// Make sure the address is aligned, or this function will abort.
template <typename T> T &ref(wasm_ptr_t array_address, wasm_size_t array_index) const noexcept {
return ref<T>(array_address + array_index * sizeof(T));
}
@ -373,7 +396,7 @@ namespace mkxp_sandbox {
void strcpy(wasm_ptr_t dst_address, const char *src) const noexcept;
// Copies a string into a sandbox memory address.
void strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept;
void strncpy_s(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept;
// Copies an array of length `num_elements` into a sandbox memory address.
template <typename T> void arycpy(wasm_ptr_t dst_address, const T *src, wasm_size_t num_elements) const noexcept {

View file

@ -19,6 +19,7 @@
** along with mkxp. If not, see <http://www.gnu.org/licenses/>.
*/
#include <algorithm>
#include "bitmap-binding.h"
#include "disposable-binding.h"
#include "etc-binding.h"
@ -406,7 +407,12 @@ static VALUE get_raw_data(VALUE self) {
SANDBOX_AWAIT_S(1, rb_str_new_cstr, "");
SANDBOX_AWAIT(rb_str_resize, SANDBOX_SLOT(1), SANDBOX_SLOT(2));
SANDBOX_AWAIT_S(0, rb_string_value_ptr, &SANDBOX_SLOT(1));
SANDBOX_GUARD_L(bitmap->getRaw(sb().e, sb()->ptr(SANDBOX_SLOT(0)), SANDBOX_SLOT(2)));
#ifdef MKXPZ_BIG_ENDIAN
SANDBOX_GUARD_L(bitmap->getRaw(sb().e, &sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(2), (int32_t)1) - 1), SANDBOX_SLOT(2)));
std::reverse(&sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(2), (int32_t)1) - 1), &sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(2), (int32_t)1) - 1) + SANDBOX_SLOT(2));
#else
SANDBOX_GUARD_L(bitmap->getRaw(sb().e, &sb()->ref<uint8_t>(SANDBOX_SLOT(0)), SANDBOX_SLOT(2)));
#endif // MKXPZ_BIG_ENDIAN
}
return SANDBOX_SLOT(1);
@ -418,13 +424,18 @@ static VALUE get_raw_data(VALUE self) {
static VALUE set_raw_data(VALUE self, VALUE value) {
struct coro : boost::asio::coroutine {
typedef decl_slots<wasm_ptr_t, wasm_size_t> slots;
typedef decl_slots<wasm_ptr_t, int32_t> slots;
VALUE operator()(VALUE self, VALUE value) {
BOOST_ASIO_CORO_REENTER (this) {
SANDBOX_AWAIT_S(0, rb_string_value_ptr, &value);
SANDBOX_AWAIT_S(1, get_bytesize, value);
SANDBOX_GUARD_L(get_private_data<Bitmap>(self)->replaceRaw(sb().e, sb()->ptr(SANDBOX_SLOT(0)), SANDBOX_SLOT(1)));
#ifdef MKXPZ_BIG_ENDIAN
SANDBOX_GUARD_L(get_private_data<Bitmap>(self)->replaceRaw(sb().e, &sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (int32_t)1) - 1), SANDBOX_SLOT(1)));
std::reverse(&sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (int32_t)1) - 1), &sb()->ref<uint8_t>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (int32_t)1) - 1) + SANDBOX_SLOT(1));
#else
SANDBOX_GUARD_L(get_private_data<Bitmap>(self)->replaceRaw(sb().e, &sb()->ref<uint8_t>(SANDBOX_SLOT(0)), SANDBOX_SLOT(1)));
#endif // MKXPZ_BIG_ENDIAN
}
return self;

View file

@ -22,6 +22,7 @@
#ifndef MKXPZ_SANDBOX_SERIALIZABLE_BINDING_H
#define MKXPZ_SANDBOX_SERIALIZABLE_BINDING_H
#include <algorithm>
#include "binding-util.h"
namespace mkxp_sandbox {
@ -34,7 +35,12 @@ namespace mkxp_sandbox {
SANDBOX_AWAIT_S(2, rb_obj_alloc, klass);
SANDBOX_AWAIT_S(0, rb_string_value_ptr, &src);
SANDBOX_AWAIT_S(1, get_bytesize, src);
SANDBOX_GUARD(set_private_data(sb().e, SANDBOX_SLOT(2), C::deserialize(sb().e, (const char *)sb()->ptr(SANDBOX_SLOT(0)), SANDBOX_SLOT(1))));
#ifdef MKXPZ_BIG_ENDIAN
SANDBOX_GUARD(set_private_data(sb().e, SANDBOX_SLOT(2), C::deserialize(sb().e, &sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1), SANDBOX_SLOT(1))));
std::reverse(&sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1), &sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1) + SANDBOX_SLOT(1));
#else
SANDBOX_GUARD(set_private_data(sb().e, SANDBOX_SLOT(2), C::deserialize(sb().e, &sb()->ref<char>(SANDBOX_SLOT(0)), SANDBOX_SLOT(1))));
#endif // MKXPZ_BIG_ENDIAN
}
return SANDBOX_SLOT(2);
@ -54,7 +60,12 @@ namespace mkxp_sandbox {
SANDBOX_AWAIT_S(2, rb_str_new_cstr, "");
SANDBOX_AWAIT(rb_str_resize, SANDBOX_SLOT(2), SANDBOX_SLOT(1));
SANDBOX_AWAIT_S(0, rb_string_value_ptr, &SANDBOX_SLOT(2));
get_private_data<C>(self)->serialize((char *)sb()->ptr(SANDBOX_SLOT(0)));
#ifdef MKXPZ_BIG_ENDIAN
get_private_data<C>(self)->serialize(&sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1));
std::reverse(&sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1), &sb()->ref<char>(SANDBOX_SLOT(0), std::max(SANDBOX_SLOT(1), (wasm_size_t)1) - 1) + SANDBOX_SLOT(1));
#else
get_private_data<C>(self)->serialize(&sb()->ref<char>(SANDBOX_SLOT(0)));
#endif // MKXPZ_BIG_ENDIAN
}
return SANDBOX_SLOT(2);

View file

@ -138,10 +138,6 @@ void wasi_t::deallocate_file_descriptor(uint32_t fd) {
}
}
void *wasi_t::ptr(wasm_ptr_t address) const noexcept {
return sandbox_ptr(*ruby, address);
}
wasm_size_t wasi_t::strlen(wasm_ptr_t address) const noexcept {
return sandbox_strlen(*ruby, address);
}
@ -150,8 +146,8 @@ void wasi_t::strcpy(wasm_ptr_t dst_address, const char *src) const noexcept {
sandbox_strcpy(*ruby, dst_address, src);
}
void wasi_t::strncpy(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept {
sandbox_strncpy(*ruby, dst_address, src, max_size);
void wasi_t::strncpy_s(wasm_ptr_t dst_address, const char *src, wasm_size_t max_size) const noexcept {
sandbox_strncpy_s(*ruby, dst_address, src, max_size);
}
struct mkxp_sandbox::sandbox_str_guard wasi_t::str(wasm_ptr_t address) const noexcept {
@ -550,7 +546,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_prestat_dir_name(wasi_t *was
return WASI_EBADF;
case wasi_fd_type::FS:
wasi->strncpy(path, wasi->fdtable[fd].dir_handle()->path.c_str(), path_len + 1);
wasi->strncpy_s(path, wasi->fdtable[fd].dir_handle()->path.c_str(), path_len + 1);
return WASI_ESUCCESS;
case wasi_fd_type::STDIN:
@ -621,17 +617,21 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_read(wasi_t *wasi, uint32_t
{
uint32_t size = 0;
while (iovs_len > 0) {
uint8_t *ptr = (uint8_t *)wasi->ptr(wasi->ref<uint32_t>(iovs));
uint32_t ptr = wasi->ref<uint32_t>(iovs);
uint32_t length = wasi->ref<uint32_t>(iovs + 4);
if (length > 0) {
#ifdef MKXPZ_BIG_ENDIAN
ptr -= length;
uint8_t *buffer = &wasi->ref<uint8_t>(ptr, length - 1);
#else
uint8_t *buffer = &wasi->ref<uint8_t>(ptr);
#endif // MKXPZ_BIG_ENDIAN
PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->file.get(), ptr, length);
PHYSFS_sint64 n = PHYSFS_readBytes(wasi->fdtable[fd].file_handle()->file.get(), buffer, length);
#ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length);
std::reverse(buffer, buffer + length);
#endif // MKXPZ_BIG_ENDIAN
if (n < 0) return WASI_EIO;
size += n;
if (n < 0) return WASI_EIO;
size += n;
}
iovs += 8;
--iovs_len;
}
@ -694,29 +694,13 @@ 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;
}
std::memcpy(
#ifdef MKXPZ_BIG_ENDIAN
wasi->ptr(edata->buf + 8),
#else
wasi->ptr(edata->buf),
#endif // MKXPZ_BIG_ENDIAN
&edata->cookie,
8
);
std::memcpy(wasi->ptr_unaligned<uint64_t>(edata->buf), &edata->cookie, 8);
edata->buf += 8;
if (edata->buf - edata->original_buf + 8 > edata->buf_len) {
return PHYSFS_ENUM_STOP;
}
std::memset(
#ifdef MKXPZ_BIG_ENDIAN
wasi->ptr(edata->buf + 8),
#else
wasi->ptr(edata->buf),
#endif // MKXPZ_BIG_ENDIAN
0,
8
);
std::memset(wasi->ptr_unaligned<uint64_t>(edata->buf), 0, 8);
edata->buf += 8;
if (edata->buf - edata->original_buf + 4 > edata->buf_len) {
@ -724,15 +708,7 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_readdir(wasi_t *wasi, uint32
}
{
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
);
std::memcpy(wasi->ptr_unaligned<uint32_t>(edata->buf), &value, 4);
}
edata->buf += 4;
@ -908,18 +884,21 @@ extern "C" uint32_t w2c_wasi__snapshot__preview1_fd_write(wasi_t *wasi, uint32_t
}
uint32_t size = 0;
while (iovs_len > 0) {
uint8_t *ptr = (uint8_t *)wasi->ptr(wasi->ref<uint32_t>(iovs));
uint32_t ptr = wasi->ref<uint32_t>(iovs);
uint32_t length = wasi->ref<uint32_t>(iovs + 4);
if (length > 0) {
#ifdef MKXPZ_BIG_ENDIAN
ptr -= length;
std::reverse(ptr, ptr + length);
uint8_t *buffer = &wasi->ref<uint8_t>(ptr, length - 1);
#else
uint8_t *buffer = &wasi->ref<uint8_t>(ptr);
#endif // MKXPZ_BIG_ENDIAN
PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->file.get_write(), ptr, length);
PHYSFS_sint64 n = PHYSFS_writeBytes(wasi->fdtable[fd].file_handle()->file.get_write(), buffer, length);
#ifdef MKXPZ_BIG_ENDIAN
std::reverse(ptr, ptr + length);
std::reverse(buffer, buffer + length);
#endif // MKXPZ_BIG_ENDIAN
if (n >= 0) {
size += n;
if (n > 0) {
size += n;
}
}
iovs += 8;
--iovs_len;

View file

@ -210,14 +210,25 @@ typedef struct w2c_wasi__snapshot__preview1 {
void deallocate_file_descriptor(uint32_t fd);
// Gets a pointer to the given address in sandbox memory.
void *ptr(mkxp_sandbox::wasm_ptr_t address) const noexcept;
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *ptr_unaligned(mkxp_sandbox::wasm_ptr_t address) const noexcept {
return mkxp_sandbox::sandbox_ptr_unaligned<T>(*ruby, address);
}
// Gets a pointer to the given index in the array at a given address in sandbox memory.
// Unlike `sandbox_ref`, the address does not need to be aligned.
template <typename T> void *ptr_unaligned(mkxp_sandbox::wasm_ptr_t array_address, mkxp_sandbox::wasm_size_t array_index) const noexcept {
return mkxp_sandbox::sandbox_ptr_unaligned<T>(*ruby, array_address, array_index);
}
// Gets a reference to the value stored at a given address in sandbox memory.
// Make sure the address is aligned, or this function will abort.
template <typename T> T &ref(mkxp_sandbox::wasm_ptr_t address) const noexcept {
return mkxp_sandbox::sandbox_ref<T>(*ruby, address);
}
// Gets a reference to the value stored at the given index in the array at a given address in sandbox memory.
// Make sure the address is aligned, or this function will abort.
template <typename T> T &ref(mkxp_sandbox::wasm_ptr_t array_address, mkxp_sandbox::wasm_size_t array_index) const noexcept {
return ref<T>(array_address + array_index * sizeof(T));
}
@ -232,7 +243,7 @@ typedef struct w2c_wasi__snapshot__preview1 {
void strcpy(mkxp_sandbox::wasm_ptr_t dst_address, const char *src) const noexcept;
// Copies a string into a sandbox memory address.
void strncpy(mkxp_sandbox::wasm_ptr_t dst_address, const char *src, mkxp_sandbox::wasm_size_t max_size) const noexcept;
void strncpy_s(mkxp_sandbox::wasm_ptr_t dst_address, const char *src, mkxp_sandbox::wasm_size_t max_size) const noexcept;
// Copies an array of length `num_elements` into a sandbox memory address.
template <typename T> void arycpy(mkxp_sandbox::wasm_ptr_t dst_address, const T *src, mkxp_sandbox::wasm_size_t num_elements) const noexcept {

View file

@ -2306,10 +2306,6 @@ bool Bitmap::getRaw(Exception &exception, void *output, int output_size)
Debug() << "GAME BUG: Game is calling getRaw on low-res Bitmap; you may want to patch the game to improve graphics quality.";
}
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
output = (uint8_t *)output - output_size;
#endif
if (!p->animation.enabled && (p->surface || p->megaSurface)) {
void *src = (p->megaSurface) ? p->megaSurface->pixels : p->surface->pixels;
memcpy(output, src, output_size);
@ -2319,10 +2315,6 @@ bool Bitmap::getRaw(Exception &exception, void *output, int output_size)
gl.ReadPixels(0,0,width(),height(),GL_RGBA,GL_UNSIGNED_BYTE,output);
}
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
std::reverse((uint8_t *)output, (uint8_t *)output + output_size);
#endif
return true;
}
@ -2345,18 +2337,9 @@ void Bitmap::replaceRaw(Exception &exception, void *pixel_data, int size)
return;
}
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
pixel_data = (uint8_t *)pixel_data - size;
std::reverse((uint8_t *)pixel_data, (uint8_t *)pixel_data + size);
#endif
TEX::bind(getGLTypes().tex);
TEX::uploadImage(w, h, pixel_data, GL_RGBA);
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
std::reverse((uint8_t *)pixel_data, (uint8_t *)pixel_data + size);
#endif
#ifdef MKXPZ_RETRO
p->pushDiff(pixel_data, rect());
#endif // MKXPZ_RETRO

View file

@ -129,13 +129,8 @@ void Table::serialize(char *buffer) const
writeInt32(&buffer, zs);
writeInt32(&buffer, size);
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
for (const int16_t datum : data)
*(int16_t *)(buffer -= sizeof(int16_t)) = datum;
#else
if (size > 0)
memcpy(buffer, dataPtr(data), sizeof(int16_t)*size);
#endif
}
@ -167,13 +162,8 @@ Table *Table::deserialize(Exception &exception, const char *data, int len)
Table *t = new Table(x, y, z);
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
for (int16_t &datum : t->data)
datum = *(int16_t *)(data -= sizeof(int16_t));
#else
if (size > 0)
memcpy(dataPtr(t->data), data, sizeof(int16_t)*size);
#endif
return t;
}

View file

@ -31,15 +31,10 @@ readInt32(const char **dataP)
{
int32_t result;
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
*dataP -= 4;
memcpy(&result, *dataP, 4);
#else
memcpy(&result, *dataP, 4);
*dataP += 4;
#endif
#if !defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
#ifdef MKXPZ_BIG_ENDIAN
# ifdef _MSC_VER
static_assert(sizeof(unsigned long) == sizeof(int32_t), "unsigned long should be 32 bits");
result = (int32_t)_byteswap_ulong((unsigned long)result);
@ -54,7 +49,7 @@ readInt32(const char **dataP)
static inline double
readDouble(const char **dataP)
{
#if !defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
#ifdef MKXPZ_BIG_ENDIAN
uint64_t result;
memcpy(&result, *dataP, 8);
@ -70,13 +65,8 @@ readDouble(const char **dataP)
#else
double result;
# if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
*dataP -= 8;
memcpy(&result, *dataP, 8);
# else
memcpy(&result, *dataP, 8);
*dataP += 8;
# endif
return result;
#endif
@ -85,7 +75,7 @@ readDouble(const char **dataP)
static inline void
writeInt32(char **dataP, int32_t value)
{
#if !defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
#ifdef MKXPZ_BIG_ENDIAN
# ifdef _MSC_VER
static_assert(sizeof(unsigned long) == sizeof(int32_t), "unsigned long should be 32 bits");
value = (int32_t)_byteswap_ulong((unsigned long)value);
@ -94,19 +84,14 @@ writeInt32(char **dataP, int32_t value)
# endif
#endif
#if defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
*dataP -= 4;
memcpy(*dataP, &value, 4);
#else
memcpy(*dataP, &value, 4);
*dataP += 4;
#endif
}
static inline void
writeDouble(char **dataP, double value)
{
#if !defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
#ifdef MKXPZ_BIG_ENDIAN
uint64_t valueUint = *(uint64_t *)&value;
# ifdef _MSC_VER
@ -116,14 +101,10 @@ writeDouble(char **dataP, double value)
# endif
memcpy(*dataP, &valueUint, 8);
*dataP += 8;
#elif defined(MKXPZ_RETRO) && defined(MKXPZ_BIG_ENDIAN)
*dataP -= 8;
memcpy(*dataP, &value, 8);
#else
memcpy(*dataP, &value, 8);
*dataP += 8;
#endif
*dataP += 8;
}
#endif // SERIALUTIL_H