Skip to content

Prevent some infinite recursion and loops - #352

Merged
IsaacWoods merged 1 commit into
rust-osdev:mainfrom
martin-hughes:prevent-infinite-recursion
Sep 21, 2026
Merged

IsaacWoods merged 1 commit into
rust-osdev:mainfrom
martin-hughes:prevent-infinite-recursion

Conversation

@martin-hughes

Copy link
Copy Markdown
Contributor

The motivation is to help stop AML causing a thread (or the system as a whole) to become deadlocked.

The first protection adds a maximum method call stack depth. This has been chosen arbitrarily, for now. It does not protect against all possible ways of recursing infinitely. For example, it does not stop recursive table loads. (Although LoadTable is not currently supported)

The second protection is a straightforward timeout for while loops, with associated tests.

These are both based on the uACPI protections, although they differ in a key way: in uACPI, the method stack is unwound. If a table definition is reached, execution continues with the next statement, but the execution is still flagged as failed. In this crate, execution is stopped with an error.

Notes:

  • I haven't made these configurable, for now. That could be valuable follow-on work if we see these limits being a problem.
  • I did wonder about enforcing a method execution timeout. But I wasn't sure what would happen if the system went to sleep and woke up a long time later. uACPI doesn't have such a timeout which made me feel better about leaving it out
  • I considered adding reference unwrapping limits as well, but they'd need to change the signatures of the unwrap_ methods, so I felt that was worth leaving for a separate PR.

Comment thread tests/while.asl

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The actual tests are the same, but now the "shoulds" have become "musts".

Panicked,
}

impl<T> std::fmt::Debug for RunTestResult<T>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Needed to allow RunTestResult to be checked in assert_matches

Comment thread src/aml/mod.rs
kind: BlockKind::Method { method_scope: scope.clone() },
};
let block =
Block { stream: code.clone(), pc: 0, kind: BlockKind::Method { method_scope: scope.clone() } };

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a pure formatting change - I'm not sure why the previous version was unacceptable to rustfmt. Maybe it's a new-nightly thing?

@martin-hughes

Copy link
Copy Markdown
Contributor Author

Whoever merges this PR: it will interact with #345. The second of the two to be merged will need updating to handle the first.

The motivation is to help stop AML causing a thread (or the system as a
whole) to become deadlocked.

The first protection adds a maximum method call stack depth. This has
been chosen arbitrarily, for now. It does not protect against all
possible ways of recursing infinitely. For example, it does not stop
recursive table loads. (Although LoadTable is not currently supported)

The second protection is a straightforward timeout for while loops,
with associated tests.

These are both based on the uACPI protections, although they differ in
a key way: in uACPI, the method stack is unwound. If a table definition
is reached, execution continues with the next statement, but the
execution is still flagged as failed. In this crate, execution is
stopped with an error.
@martin-hughes
martin-hughes force-pushed the prevent-infinite-recursion branch from d4b3c42 to db22136 Compare September 19, 2026 09:39
@martin-hughes

Copy link
Copy Markdown
Contributor Author

Rebased on top of the updated main since #345 has been merged.

@IsaacWoods IsaacWoods left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice, thanks for working on this! I think both limits reasonable - wondered between max loop iterators vs timeout, but I think total time spent in the loop is a better metric for something stuck.

Whether anything reasonable (in the land of AML) would require stack depths >1000... who knows. I'd hope not, so let's go with this initially.

Comment thread src/aml/mod.rs
Ok(PciAddress::new(seg as u16, bus as u8, device as u8, function as u8))
}

/// Return to the beginning of a While loop - either because `Continue` was executed or

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice :)


fn stall(&self, microseconds: u64) {
// There's no `std` equivalent to stall, and sleep is probably OK for a test environment.
sleep(Duration::from_micros(microseconds / self.scale_factor));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

For testing, I don't think this matters too much and can't remember the details (or when you start worrying; but I do think <1ms is probably about there) but Windows in particular is very bad at short waits.

Potentially the right way to do this is via something like the spin_sleep crate, which manually uses higher-precision timers if available, or alternatively spins for short sleeps that are under the native timer's precision.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good shout - I'll bear this in mind if it becomes a problem!

I think Windows rounds delays up to at least a scheduler period because it yields the thread, and the timer resolution is a handful of millis in any case. I think in test land it'll probably be OK unless we're getting down to debugging some kind of race condition.

@IsaacWoods
IsaacWoods merged commit d3c23bb into rust-osdev:main Sep 21, 2026
6 checks passed
@martin-hughes
martin-hughes deleted the prevent-infinite-recursion branch September 21, 2026 20:09
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