Skip to content

Allow aml_tester to continue after an interpreter panic#277

Merged
IsaacWoods merged 4 commits intorust-osdev:mainfrom
martin-hughes:aml-tester-tolerate-panic
Mar 22, 2026
Merged

Allow aml_tester to continue after an interpreter panic#277
IsaacWoods merged 4 commits intorust-osdev:mainfrom
martin-hughes:aml-tester-tolerate-panic

Conversation

@martin-hughes
Copy link
Copy Markdown
Contributor

The motivation here is to allow testing of large numbers of AML files - before this PR, a panic (probably from the Interpreter) would stop testing of all remaining files as aml_tester would exit.

It has evolved into a slightly larger PR than that, with a grab-bag of other minor updates listed below.

The main bit of this PR all flows from changes to run_test:

  • To allow testing to continue after a panic, I use catch_unwind.
  • If an unwind is caught, the Interpreter will not necessarily be in a valid state
  • We therefore don't want to re-use it for future tests
  • run_tests needs to take ownership of the interpreter so it can enforce this rule

This leads to a variety of parameter and return type changes throughout. (And explains why there's a bunch of new enums in the code)

Then I made a few other changes to improve consistency:

  • resolve_and_compile doesn't return io::Result any more - that level of detail isn't needed by the caller
  • This helped neaten up the output if there was a compilation error

Finally, because they were looking a bit messy:

  • I removed the %FN% interpolation - actually resolve_and_compile already relied on the iasl file-naming behaviour, so the only valid thing that could go in %FN% was what resolve_and_compile would already need. So it added no real value.
  • aml_tester::main now returns an exit code, so that if there are any test failures the user can see it reflected there. This might be useful for CI pipelines etc and reflects other testing tools (e.g. cargo test)

@martin-hughes
Copy link
Copy Markdown
Contributor Author

The exit code change already showing its value by breaking the checks it seems!

Not sure why yet, I'll fix and update the PR - it works for me on my machine 👀

@martin-hughes
Copy link
Copy Markdown
Contributor Author

Well I can see to_x.asl actually silently fails on at least PR #274 (CI tests are green despite test failure) - some testing with WSL suggests it's a difference in the output from different iasl versions.

WSL Ubuntu apt install acpica-tools version: 20200925 - generates to_x.aml that fails when run in aml_tester
Windows reasonably recent version directly downloaded: 20251212 - generates to_x.aml that succeeds.

I'm not sure where to go from there really.

@martin-hughes
Copy link
Copy Markdown
Contributor Author

Alright, I've figured out the problem. iasl was folding out the calls to ToHexString in the optimizer, and different versions of iasl produced different results for that - the new one produces (e.g.) "0x7b" whereas the old one produces "0000007b".

So I've added the -oa flag to the call to iasl and now it doesn't do that folding - I think this is the correct flag, just in case any optimisation hides the test we're trying to do. (Not just the constant folding optimisations)

This requires a minor fix to ToHexString to match the expected upper case, but it has exposed a bug in ToInteger that I've raised #278 rather than fixing here.

@martin-hughes
Copy link
Copy Markdown
Contributor Author

I've added the fix for #278 here to simplify testing it, let me know if you'd prefer it as a separate PR - I know this has a lot going on now... (Would close #278 if merged)

Copy link
Copy Markdown
Member

@IsaacWoods IsaacWoods left a comment

Choose a reason for hiding this comment

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

Thanks! This is a nice addition - one of my next goals with the library is to effectively eliminate panics, as a nice guarantee to users would be that the interpreter will never panic a kernel, but in the medium-term it would be nice to be able to recover from them in tests.

I've left a few comments with some refactoring nits, but otherwise this looks good. I'm fine with including the ToInteger changes here - thanks for working on that! It didn't occur to me that iasl would be applying optimisations (maybe when I looked it didn't do them if there have been changes in the last couple years?).

History wise, would it be possible to rebase to merge the first four commits into one? I think that makes intentions clearer with the intermediary changes eliminated.


/// The result of a call to [`run_test`]. This is a bit of a combination - it contains the actual
/// result of the test, but also the interpreter - if it is still valid.
pub enum RunTestResult<T>
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.

Having these two enums split is a little confusing I think. I wonder if it would be cleaner to have a return type of (TestResult, Option<Interpreter>) from the relevant functions to replace RunTestResult??

We could then optionally merge TestFailureReason into this too (i.e. have multiple FailedX variants in here. We could always have a TestResult::is_failure method if needed. I do like including the AmlError if applicable though.

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 reason I didn't go for the tuple approach is that the combined enum enforces the correct handling of the Interpreter. That is, it's not possible to get a (TestResult::Pass, None) or (TestResult::Panicked, Some(...)) result, so no code is needed to deal with it - not even an unwrap().

Just a personal style thing I guess - I'm a big fan of type-based enforcement of things - so if you prefer I'll take it out. Let me know if my argument sways you or not 😄

I don't feel too strongly about merging TestFailure reason into the enum - I guess if RunTestResult stays then it reduces duplication... I'll play it by ear based on what you say.

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.

That seems fair enough on second look - I think this is fine!

Object::Integer(other) => {
error!("Test _MAIN returned non-zero exit code: {}", other);
// TODO: wrong error - this should probs return a more complex err type
Err(AmlError::NoCurrentOp)
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.

I am not sure what we should use for this, but I feel leaving it like this could be confusing. I wonder if we should introduce an AmlError::HostError(String) (bikeshedding of name welcome) for this + errors that occur during handler operations?

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.

Yes - good shout. As you can see from the comment, totally meant to do something like this! My original thought was something more complex, but I think you've got a good solution.

_ => {
error!("Test _MAIN returned unexpected object type: {}", *result);
// TODO: wrong error
Err(AmlError::NoCurrentOp)
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.

Same as above.

@martin-hughes
Copy link
Copy Markdown
Contributor Author

Cheers Isaac. Let me know about RunTestResult - I'll deal with it whichever way you say, then deal with squashing the first 4 commits later.

one of my next goals with the library is to effectively eliminate panics, as a nice guarantee to users would be that the interpreter will never panic a kernel, but in the medium-term it would be nice to be able to recover from them in tests.

Good plan, that'd be a nice guarantee to have - I guess most of the todo could be replaced by AmlError::LibUnimplemented or similar?

O/T really, but some good news: from a play with the uACPI tests and a not-yet-ready update to aml_tester it only looks like there's a couple of todo that get hit regularly. From memory I don't think I saw any of the unwrap calls get triggered.

Fix accidentally broken tests

Exit with a failure code if needed

This makes it easier for any user to see if a test has failed. Which may
be useful for example in CI environments.

Remove AML filename replacement

`resolve_and_compile` relies on the current `iasl` way of naming its
output, there's no need to duplicate that in `create_script_file`
This was masking some bugs in `ToHexString` and `ToInteger` because
those calls were being folded out by the iasl optimizer.
@martin-hughes martin-hughes force-pushed the aml-tester-tolerate-panic branch from 2a1f120 to 92db67c Compare March 22, 2026 11:56
@martin-hughes
Copy link
Copy Markdown
Contributor Author

Cheers Isaac. First 4 commits squashed, so should be good to go 🤞

@IsaacWoods IsaacWoods merged commit a516e3c into rust-osdev:main Mar 22, 2026
5 checks passed
@martin-hughes martin-hughes deleted the aml-tester-tolerate-panic branch March 22, 2026 19:59
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