LibWasm: Fix validation of if-else blocks

We were doing a number of things wrong:
- Switching to the parent context in the else meant that we couldn't
  break out of the else section anymore
- We were not validating the resulting values, and so the stack was
  in a relatively unknown state after 'else'

This commit fixes these issues :^)
This commit is contained in:
Ali Mohammad Pur 2022-02-15 17:32:13 +03:30 committed by Ali Mohammad Pur
parent 385b07dcda
commit eccdf4eb4b
Notes: sideshowbarker 2024-07-18 00:34:07 +09:00
2 changed files with 33 additions and 15 deletions

View File

@ -2382,20 +2382,28 @@ VALIDATE_INSTRUCTION(structured_end)
m_context = m_parent_contexts.take_last();
auto last_block_type = m_entered_blocks.take_last();
if (last_scope == ChildScopeKind::Block) {
auto details = m_block_details.take_last();
// FIXME: Validate the returns.
return {};
switch (last_scope) {
case ChildScopeKind::Block:
case ChildScopeKind::IfWithoutElse:
case ChildScopeKind::Else:
m_block_details.take_last();
break;
case ChildScopeKind::IfWithElse:
return Errors::invalid("usage of if without an else clause that appears to have one anyway");
}
if (last_scope == ChildScopeKind::Else) {
auto details = m_block_details.take_last().details.get<BlockDetails::IfDetails>();
if (details.true_branch_stack != stack)
return Errors::invalid("stack configuration after if-else", details.true_branch_stack.release_vector(), stack.release_vector());
auto& results = last_block_type.results();
if (results.size() > stack.size())
return Errors::invalid_stack_state();
return {};
for (size_t i = 1; i <= results.size(); ++i) {
if (stack.take_last() != results[results.size() - i])
return Errors::invalid_stack_state();
}
for (auto& result : results)
stack.append(result);
return {};
}
@ -2408,10 +2416,20 @@ VALIDATE_INSTRUCTION(structured_else)
if (m_entered_scopes.last() != ChildScopeKind::IfWithElse)
return Errors::invalid("usage of structured else");
auto& block_type = m_entered_blocks.last();
auto& results = block_type.results();
if (results.size() > stack.size())
return Errors::invalid_stack_state();
for (size_t i = 1; i <= results.size(); ++i) {
if (stack.take_last() != results[results.size() - i])
return Errors::invalid_stack_state();
}
auto& details = m_block_details.last().details.get<BlockDetails::IfDetails>();
m_entered_scopes.last() = ChildScopeKind::Else;
auto& if_details = m_block_details.last().details.get<BlockDetails::IfDetails>();
if_details.true_branch_stack = exchange(stack, move(if_details.initial_stack));
m_context = m_parent_contexts.last();
stack = move(details.initial_stack);
return {};
}
@ -2473,6 +2491,8 @@ VALIDATE_INSTRUCTION(if_)
if (stack.is_empty() || !stack.take_last().is_of_kind(ValueType::I32))
return Errors::invalid_stack_state();
auto stack_snapshot = stack;
auto& parameters = block_type.parameters();
if (stack.size() < parameters.size())
return Errors::invalid_stack_state();
@ -2486,7 +2506,7 @@ VALIDATE_INSTRUCTION(if_)
stack.append(parameter);
m_entered_scopes.append(args.else_ip.has_value() ? ChildScopeKind::IfWithElse : ChildScopeKind::IfWithoutElse);
m_block_details.empend(stack.actual_size(), BlockDetails::IfDetails { stack, {} });
m_block_details.empend(stack.actual_size(), BlockDetails::IfDetails { move(stack_snapshot) });
m_parent_contexts.append(m_context);
m_entered_blocks.append(block_type);
m_context.labels.prepend(ResultType { block_type.results() });

View File

@ -260,7 +260,6 @@ private:
enum class ChildScopeKind {
Block,
Loop,
IfWithoutElse,
IfWithElse,
Else,
@ -270,7 +269,6 @@ private:
size_t initial_stack_size { 0 };
struct IfDetails {
Stack initial_stack;
Stack true_branch_stack;
};
Variant<IfDetails, Empty> details;
};