Skip to content

Commit

Permalink
refactor(traverse): harden soundness of Traverse and document safet…
Browse files Browse the repository at this point in the history
…y invariants better (#8507)

Harden soundness of `Traverse` by:

1. Not exposing `walk_*` methods outside of `walk.rs`.
2. Adding more debug assertions.
3. Adding `#[must_use]` to `TraverseAncestry::push_stack`, so we'll get a lint error if codegen-ed code pushes to `TraverseAncestry`'s stack and doesn't pop it off again.

Document the safety invariants better.
  • Loading branch information
overlookmotel committed Jan 15, 2025
1 parent 8b6d331 commit a368726
Show file tree
Hide file tree
Showing 4 changed files with 289 additions and 233 deletions.
21 changes: 18 additions & 3 deletions crates/oxc_traverse/scripts/lib/walk.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,24 @@ export default function generateWalkFunctionsCode(types) {
use crate::{ancestor::{self, AncestorType}, Ancestor, Traverse, TraverseCtx};
/// Walk AST with \`Traverse\` impl.
///
/// SAFETY:
/// * \`program\` must be a pointer to a valid \`Program\` which has lifetime \`'a\`
/// (\`Program<'a>\`).
/// * \`ctx\` must contain a \`TraverseAncestry<'a>\` with single \`Ancestor::None\` on its stack.
#[inline]
pub(crate) unsafe fn walk_ast<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
program: *mut Program<'a>,
ctx: &mut TraverseCtx<'a>,
) {
walk_program(traverser, program, ctx);
}
${walkMethods}
pub(crate) unsafe fn walk_statements<'a, Tr: Traverse<'a>>(
unsafe fn walk_statements<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
stmts: *mut Vec<'a, Statement<'a>>,
ctx: &mut TraverseCtx<'a>
Expand Down Expand Up @@ -254,7 +269,7 @@ function generateWalkForStruct(type, types) {

const typeSnakeName = camelToSnake(type.name);
return `
pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut ${type.rawName},
ctx: &mut TraverseCtx<'a>
Expand Down Expand Up @@ -319,7 +334,7 @@ function generateWalkForEnum(type, types) {

const typeSnakeName = camelToSnake(type.name);
return `
pub(crate) unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
unsafe fn walk_${typeSnakeName}<'a, Tr: Traverse<'a>>(
traverser: &mut Tr,
node: *mut ${type.rawName},
ctx: &mut TraverseCtx<'a>
Expand Down
1 change: 1 addition & 0 deletions crates/oxc_traverse/src/context/ancestry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ impl<'a> TraverseAncestry<'a> {
/// # SAFETY
/// This method must not be public outside this crate, or consumer could break safety invariants.
#[inline]
#[must_use] // `PopToken` must be passed to `pop_stack` to pop this entry off the stack again
pub(crate) fn push_stack(&mut self, ancestor: Ancestor<'a, 'static>) -> PopToken {
self.stack.push(ancestor);

Expand Down
Loading

0 comments on commit a368726

Please sign in to comment.