Skip to content

Commit 95591ed

Browse files
committed
Fix: flat type storage limited to MAX_FLAT_PARAMS for edge case
1 parent af69fb8 commit 95591ed

5 files changed

Lines changed: 91 additions & 66 deletions

File tree

crates/environ/src/component/types.rs

Lines changed: 70 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -377,12 +377,15 @@ impl ComponentTypes {
377377
///
378378
/// As per the Canonical ABI, when the representation is larger than MAX_FLAT_RESULTS
379379
/// or MAX_FLAT_PARAMS, the core wasm function will take a pointer to the arg/result list.
380-
/// Returns (param_iterator, result_iterator)
380+
/// Returns (param_storage, result_storage)
381381
pub fn flat_func_type(
382382
&self,
383383
ty: &TypeFunc,
384384
context: FlatFuncTypeContext,
385-
) -> (FlatTypesStorage, FlatTypesStorage) {
385+
) -> (
386+
FlatTypesStorage<MAX_FLAT_PARAMS_ABI>,
387+
FlatTypesStorage<MAX_FLAT_RESULTS_ABI>,
388+
) {
386389
let mut params_storage = self
387390
.flat_interface_type(&InterfaceType::Tuple(ty.params), MAX_FLAT_PARAMS)
388391
.unwrap_or_else(|| {
@@ -408,19 +411,23 @@ impl ComponentTypes {
408411
(params_storage, results_storage)
409412
}
410413

411-
fn flat_interface_type(&self, ty: &InterfaceType, limit: usize) -> Option<FlatTypesStorage> {
414+
fn flat_interface_type<const N: usize>(
415+
&self,
416+
ty: &InterfaceType,
417+
limit: usize,
418+
) -> Option<FlatTypesStorage<N>> {
412419
// Helper routines
413-
let push = |storage: &mut FlatTypesStorage, t32: FlatType, t64: FlatType| -> bool {
420+
let push = |storage: &mut FlatTypesStorage<N>, t32: FlatType, t64: FlatType| -> bool {
414421
storage.push(t32, t64);
415422
(storage.len as usize) <= limit
416423
};
417424

418-
let push_discrim = |storage: &mut FlatTypesStorage| -> bool {
425+
let push_discrim = |storage: &mut FlatTypesStorage<N>| -> bool {
419426
push(storage, FlatType::I32, FlatType::I32)
420427
};
421428

422429
let push_storage =
423-
|storage: &mut FlatTypesStorage, other: Option<FlatTypesStorage>| -> bool {
430+
|storage: &mut FlatTypesStorage<N>, other: Option<FlatTypesStorage<N>>| -> bool {
424431
other
425432
.and_then(|other| {
426433
let len = usize::from(storage.len);
@@ -440,45 +447,46 @@ impl ComponentTypes {
440447
// * None => No field
441448
// * Some(None) => Invalid storage (overflow)
442449
// * Some(storage) => Valid storage
443-
let push_storage_variant_case =
444-
|storage: &mut FlatTypesStorage, case: Option<Option<FlatTypesStorage>>| -> bool {
445-
match case {
446-
None => true,
447-
Some(case) => {
448-
case.and_then(|case| {
449-
// Discriminant will make size[case] = limit overshoot
450-
((1 + case.len as usize) <= limit).then(|| {
451-
// Skip 1 for discriminant
452-
let dst = storage
453-
.memory32
454-
.iter_mut()
455-
.zip(&mut storage.memory64)
456-
.skip(1);
457-
for (i, ((t32, t64), (dst32, dst64))) in case
458-
.memory32
459-
.iter()
460-
.take(case.len as usize)
461-
.zip(case.memory64.iter())
462-
.zip(dst)
463-
.enumerate()
464-
{
465-
if i + 1 < usize::from(storage.len) {
466-
// Populated Index
467-
dst32.join(*t32);
468-
dst64.join(*t64);
469-
} else {
470-
// New Index
471-
storage.len += 1;
472-
*dst32 = *t32;
473-
*dst64 = *t64;
474-
}
450+
let push_storage_variant_case = |storage: &mut FlatTypesStorage<N>,
451+
case: Option<Option<FlatTypesStorage<N>>>|
452+
-> bool {
453+
match case {
454+
None => true,
455+
Some(case) => {
456+
case.and_then(|case| {
457+
// Discriminant will make size[case] = limit overshoot
458+
((1 + case.len as usize) <= limit).then(|| {
459+
// Skip 1 for discriminant
460+
let dst = storage
461+
.memory32
462+
.iter_mut()
463+
.zip(&mut storage.memory64)
464+
.skip(1);
465+
for (i, ((t32, t64), (dst32, dst64))) in case
466+
.memory32
467+
.iter()
468+
.take(case.len as usize)
469+
.zip(case.memory64.iter())
470+
.zip(dst)
471+
.enumerate()
472+
{
473+
if i + 1 < usize::from(storage.len) {
474+
// Populated Index
475+
dst32.join(*t32);
476+
dst64.join(*t64);
477+
} else {
478+
// New Index
479+
storage.len += 1;
480+
*dst32 = *t32;
481+
*dst64 = *t64;
475482
}
476-
})
483+
}
477484
})
478-
.is_some()
479-
}
485+
})
486+
.is_some()
480487
}
481-
};
488+
}
489+
};
482490

483491
// Logic
484492
let mut storage_buf = FlatTypesStorage::new();
@@ -1364,6 +1372,15 @@ pub const MAX_FLAT_TYPES: usize = if MAX_FLAT_PARAMS > MAX_FLAT_RESULTS {
13641372
MAX_FLAT_RESULTS
13651373
};
13661374

1375+
/// Maximum number of parameters that a core wasm function exported/imports through
1376+
/// components can contain according to the Canonical ABI. In particular, this
1377+
/// can includes one potential extra return pointer for canon.lower methods.
1378+
pub const MAX_FLAT_PARAMS_ABI: usize = MAX_FLAT_PARAMS + 1;
1379+
1380+
/// Maximum number of results that a core wasm function exported/imports through
1381+
/// components can contain according to the Canonical ABI.
1382+
pub const MAX_FLAT_RESULTS_ABI: usize = MAX_FLAT_RESULTS;
1383+
13671384
const fn add_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
13681385
const MAX: u8 = MAX_FLAT_TYPES as u8;
13691386
let sum = match (a, b) {
@@ -1395,11 +1412,11 @@ const fn max_flat(a: Option<u8>, b: Option<u8>) -> Option<u8> {
13951412
/// that's 24 bytes. Otherwise `FlatType` is 1 byte large and
13961413
/// `MAX_FLAT_TYPES` is 16, so it should ideally be more space-efficient to
13971414
/// use a flat array instead of a heap-based vector.
1398-
pub struct FlatTypesStorage {
1415+
pub struct FlatTypesStorage<const N: usize> {
13991416
/// Representation for 32-bit memory
1400-
pub memory32: [FlatType; MAX_FLAT_TYPES],
1417+
pub memory32: [FlatType; N],
14011418
/// Representation for 64-bit memory
1402-
pub memory64: [FlatType; MAX_FLAT_TYPES],
1419+
pub memory64: [FlatType; N],
14031420

14041421
/// Tracks the number of flat types pushed into this storage. If this is
14051422
/// `MAX_FLAT_TYPES + 1` then this storage represents an un-reprsentable
@@ -1409,21 +1426,21 @@ pub struct FlatTypesStorage {
14091426
pub len: u8,
14101427
}
14111428

1412-
impl FlatTypesStorage {
1429+
impl<const N: usize> FlatTypesStorage<N> {
14131430
/// Create a new, empty storage for flat types
1414-
pub const fn new() -> FlatTypesStorage {
1431+
pub const fn new() -> FlatTypesStorage<N> {
14151432
FlatTypesStorage {
1416-
memory32: [FlatType::I32; MAX_FLAT_TYPES],
1417-
memory64: [FlatType::I32; MAX_FLAT_TYPES],
1433+
memory32: [FlatType::I32; N],
1434+
memory64: [FlatType::I32; N],
14181435
len: 0,
14191436
}
14201437
}
14211438

14221439
/// Returns a reference to flat type representation
14231440
pub fn as_flat_types(&self) -> Option<FlatTypes<'_>> {
14241441
let len = usize::from(self.len);
1425-
if len > MAX_FLAT_TYPES {
1426-
assert_eq!(len, MAX_FLAT_TYPES + 1);
1442+
if len > N {
1443+
assert_eq!(len, N + 1);
14271444
None
14281445
} else {
14291446
Some(FlatTypes {
@@ -1441,15 +1458,15 @@ impl FlatTypesStorage {
14411458
/// unrepresentable with a flat list of types.
14421459
pub fn push(&mut self, t32: FlatType, t64: FlatType) -> bool {
14431460
let len = usize::from(self.len);
1444-
if len < MAX_FLAT_TYPES {
1461+
if len < N {
14451462
self.memory32[len] = t32;
14461463
self.memory64[len] = t64;
14471464
self.len += 1;
14481465
true
14491466
} else {
14501467
// If this was the first one to go over then flag the length as
14511468
// being incompatible with a flat representation.
1452-
if len == MAX_FLAT_TYPES {
1469+
if len == N {
14531470
self.len += 1;
14541471
}
14551472
false

crates/environ/src/component/types_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,7 +854,7 @@ struct TypeInformationCache {
854854

855855
struct TypeInformation {
856856
depth: u32,
857-
flat: FlatTypesStorage,
857+
flat: FlatTypesStorage<MAX_FLAT_TYPES>,
858858
has_borrow: bool,
859859
}
860860

crates/wasmtime/src/runtime/component/func/host.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ use core::pin::Pin;
2222
use core::ptr::NonNull;
2323
use wasmtime_environ::component::{
2424
CanonicalAbiInfo, ComponentTypes, FlatFuncTypeContext, FlatTypesStorage, InterfaceType,
25-
MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS, OptionsIndex,
26-
RuntimeComponentInstanceIndex, TypeFunc, TypeFuncIndex, TypeTuple,
25+
MAX_FLAT_ASYNC_PARAMS, MAX_FLAT_PARAMS, MAX_FLAT_PARAMS_ABI, MAX_FLAT_RESULTS,
26+
MAX_FLAT_RESULTS_ABI, OptionsIndex, RuntimeComponentInstanceIndex, TypeFunc, TypeFuncIndex,
27+
TypeTuple,
2728
};
2829

2930
pub struct HostFunc {
@@ -220,7 +221,10 @@ fn flat_func_type(
220221
types: &ComponentTypes,
221222
ty: &TypeFunc,
222223
context: FlatFuncTypeContext,
223-
) -> (FlatTypesStorage, FlatTypesStorage) {
224+
) -> (
225+
FlatTypesStorage<MAX_FLAT_PARAMS_ABI>,
226+
FlatTypesStorage<MAX_FLAT_RESULTS_ABI>,
227+
) {
224228
types.flat_func_type(ty, context)
225229
}
226230

@@ -231,7 +235,10 @@ fn flat_func_type(
231235
_types: &ComponentTypes,
232236
_ty: &TypeFunc,
233237
_context: FlatFuncTypeContext,
234-
) -> (FlatTypesStorage, FlatTypesStorage) {
238+
) -> (
239+
FlatTypesStorage<MAX_FLAT_PARAMS_ABI>,
240+
FlatTypesStorage<MAX_FLAT_RESULTS_ABI>,
241+
) {
235242
(FlatTypesStorage::new(), FlatTypesStorage::new())
236243
}
237244

@@ -615,7 +622,7 @@ where
615622
&mut self,
616623
cx: &mut LowerContext<'_, T>,
617624
ty: InterfaceType,
618-
result_flat_types: FlatTypesStorage,
625+
result_flat_types: FlatTypesStorage<MAX_FLAT_RESULTS_ABI>,
619626
ret: R,
620627
) -> Result<()> {
621628
match self.lower_dst() {
@@ -1012,7 +1019,7 @@ unsafe fn call_host_dynamic_replay<T>(
10121019
let mut cx = LowerContext::new(store, options, instance);
10131020

10141021
// Skip lifting/lowering logic, and just replaying the lowering state
1015-
if let Some(_cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS) {
1022+
if let Some(_cnt) = result_tys.abi.flat_count(MAX_FLAT_RESULTS_ABI) {
10161023
// Copy the entire contiguous storage slice instead of looping
10171024
cx.replay_lowering(Some(storage), ReplayLoweringPhase::HostFuncReturn)?;
10181025
} else {

crates/wasmtime/src/runtime/rr/backend.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub trait RRFuncArgValsConvertable {
2121
T: FlatBytes;
2222

2323
/// Construct [`RRFuncArgVals`] from raw value buffer and a [`FlatTypesStorage`]
24-
fn from_flat_storage<T>(args: &[T], flat: FlatTypesStorage) -> RRFuncArgVals
24+
fn from_flat_storage<T, const N: usize>(args: &[T], flat: FlatTypesStorage<N>) -> RRFuncArgVals
2525
where
2626
T: FlatBytes;
2727

@@ -51,7 +51,7 @@ impl RRFuncArgValsConvertable for RRFuncArgVals {
5151

5252
/// Construct [`RRFuncArgVals`] from raw value buffer and a [`FlatTypesStorage`]
5353
#[inline]
54-
fn from_flat_storage<T>(args: &[T], flat: FlatTypesStorage) -> RRFuncArgVals
54+
fn from_flat_storage<T, const N: usize>(args: &[T], flat: FlatTypesStorage<N>) -> RRFuncArgVals
5555
where
5656
T: FlatBytes,
5757
{

crates/wasmtime/src/runtime/rr/hooks/component_hooks.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ use wasmtime_environ::WasmChecksum;
2121
#[cfg(feature = "rr")]
2222
use wasmtime_environ::component::FlatFuncTypeContext;
2323
use wasmtime_environ::component::{
24-
ComponentTypes, ExportIndex, FlatTypesStorage, InterfaceType, TypeFuncIndex,
24+
ComponentTypes, ExportIndex, FlatTypesStorage, InterfaceType, MAX_FLAT_PARAMS_ABI,
25+
MAX_FLAT_RESULTS_ABI, TypeFuncIndex,
2526
};
2627

2728
/// Indicator type signalling the context during lowering
@@ -115,7 +116,7 @@ where
115116
#[inline]
116117
pub fn record_validate_host_func_entry(
117118
args: &mut [MaybeUninit<ValRaw>],
118-
flat_params: FlatTypesStorage,
119+
flat_params: FlatTypesStorage<MAX_FLAT_PARAMS_ABI>,
119120
store: &mut StoreOpaque,
120121
) -> Result<()> {
121122
#[cfg(feature = "rr")]
@@ -132,7 +133,7 @@ pub fn record_validate_host_func_entry(
132133
#[cfg(feature = "rr")]
133134
pub fn replay_validate_host_func_entry(
134135
args: &mut [MaybeUninit<ValRaw>],
135-
flat_params: FlatTypesStorage,
136+
flat_params: FlatTypesStorage<MAX_FLAT_PARAMS_ABI>,
136137
store: &mut StoreOpaque,
137138
) -> Result<()> {
138139
#[cfg(feature = "rr")]
@@ -148,7 +149,7 @@ pub fn replay_validate_host_func_entry(
148149
#[inline]
149150
pub fn record_host_func_return(
150151
args: &[MaybeUninit<ValRaw>],
151-
flat_results: FlatTypesStorage,
152+
flat_results: FlatTypesStorage<MAX_FLAT_RESULTS_ABI>,
152153
store: &mut StoreOpaque,
153154
) -> Result<()> {
154155
#[cfg(feature = "rr")]

0 commit comments

Comments
 (0)