Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm2c: parametrize memory bounds checks on a per-memory basis #2507

Open
wants to merge 1 commit into
base: w2c-harmonize-types
Choose a base branch
from

Conversation

keithw
Copy link
Member

@keithw keithw commented Nov 11, 2024

(Sequenced behind #2506)

This PR allows "software-bounds-checked" memories and "guard-page-checked" memories to coexist in the same module.

It creates two versions of every memory operation: an unrestricted version (that works with any memory) and a _default32 version (for memories with default page size and i32 indexing).

The unrestricted version calls MEMCHECK_GENERAL, which does a 64-bit software RANGE_CHECK to check that the operation reads/writes within the bounds of the memory.

The _default32 version calls MEMCHECK_DEFAULT32, which is the same as the old MEMCHECK: if the runtime declares WASM_RT_MEMCHECK_GUARD_PAGES, it will do nothing. Otherwise it will do a 32-bit software RANGE_CHECK (which seems to be one less instruction than the 64-bit RANGE_CHECK).

This is a stepping stone to supporting custom-page-sizes (which will need to be software bounds-checked) (#2508).


#define DEFINE_STORE(name, t1, t2) \
static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \
MEMCHECK(mem, addr, t1); \
static inline void name##_unchecked(wasm_rt_memory_t* mem, u64 addr, \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a strong opinion, but would it be simpler to have something like?

#define DEFINE_STORE(name, t1, t2, MEMCHK, suffix)                                  \
  static inline void name##_##suffix(wasm_rt_memory_t* mem, u64 addr,  t2 value) {  \
    MEMCHK(mem, addr, t1);                                                          \
    t1 wrapped = (t1)value;                                                         \
    wasm_rt_memcpy(MEM_ADDR_MEMOP(mem, addr, sizeof(t1)), &wrapped, sizeof(t1));    \
  }

DEFINE_STORE(i32_store, u32, u32, MEMCHECK_DEFAULT32, _default32);
DEFINE_STORE(i32_store, u32, u32, MEMCHECK_GENERAL, _general);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I was trying to avoid the churn of duplicating every occurrence of DEFINE_LOAD/DEFINE_STORE/DEFINE_SIMD_LOAD_FUNC/DEFINE_SIMD_LOAD_LANE/DEFINE_SHARED_LOAD/etc. ... I think on balance the status quo is probably the less-bad but I don't feel that strongly either.

memory->data = addr;
#else
memory->data = calloc(byte_length, 1);
if (WASM_RT_USE_MMAP && !is64) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Might be cleaner to have

// Check if we should reallocate using mmap
#if WASM_RT_USE_MMAP
if(!is64) {
  ... // original code
  return;
}
#endif

// Fallback to malloc
memory->data = calloc(byte_length, 1);

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... I agree this one is clearer but it seemed nice to have consistency with grow_memory_impl where the early-return is harder to do. :-/

@keithw keithw force-pushed the w2c-harmonize-types branch 2 times, most recently from 487cb8a to 326e3cb Compare November 12, 2024 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants