Account for duplicated if-block params on end op in unreachable case.
This is a close analogue to bnjbvr@'s fix in commit 518b7a7e. Similar to
that fix, this PR fixes a bug in which the Wasm translator could
misalign its value stack and either mistranslate or cause a panic with a
type-checking error.
Found via fuzzing by :decoder in SpiderMonkey (bug 1664453).
This commit is contained in:
@@ -128,7 +128,9 @@ impl ControlStackFrame {
|
||||
Self::Loop { header, .. } => header,
|
||||
}
|
||||
}
|
||||
pub fn original_stack_size(&self) -> usize {
|
||||
/// Private helper. Use `truncate_value_stack_to_else_params()` or
|
||||
/// `truncate_value_stack_to_original_size()` to restore value-stack state.
|
||||
fn original_stack_size(&self) -> usize {
|
||||
match *self {
|
||||
Self::If {
|
||||
original_stack_size,
|
||||
@@ -178,6 +180,33 @@ impl ControlStackFrame {
|
||||
Self::Loop { .. } => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pop values from the value stack so that it is left at the
|
||||
/// input-parameters to an else-block.
|
||||
pub fn truncate_value_stack_to_else_params(&self, stack: &mut Vec<Value>) {
|
||||
debug_assert!(matches!(self, &ControlStackFrame::If { .. }));
|
||||
stack.truncate(self.original_stack_size());
|
||||
}
|
||||
|
||||
/// Pop values from the value stack so that it is left at the state it was
|
||||
/// before this control-flow frame.
|
||||
pub fn truncate_value_stack_to_original_size(&self, stack: &mut Vec<Value>) {
|
||||
// The "If" frame pushes its parameters twice, so they're available to the else block
|
||||
// (see also `FuncTranslationState::push_if`).
|
||||
// Yet, the original_stack_size member accounts for them only once, so that the else
|
||||
// block can see the same number of parameters as the consequent block. As a matter of
|
||||
// fact, we need to substract an extra number of parameter values for if blocks.
|
||||
let num_duplicated_params = match self {
|
||||
&ControlStackFrame::If {
|
||||
num_param_values, ..
|
||||
} => {
|
||||
debug_assert!(num_param_values <= self.original_stack_size());
|
||||
num_param_values
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
stack.truncate(self.original_stack_size() - num_duplicated_params);
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains information passed along during a function's translation and that records:
|
||||
|
||||
Reference in New Issue
Block a user