Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[debug] Add manticore::debug #123

Merged
merged 3 commits into from
Mar 30, 2022
Merged

Conversation

kesyog
Copy link
Contributor

@kesyog kesyog commented Sep 13, 2021

Started with PR #108 and made some non-structural changes to get it working:

  • Rename trace! to fail! to avoid naming conflict with log::trace.
  • Fix some minor syntax errors to get the macros to compile and work properly.

A couple of things I wasn't totally sure about:

  1. Am I correct that the advantage of the redactable log macros (info!, error!, etc.) over the base log crate is that the log crate still has some overhead ("an integer load, comparison and jump") even if no logger is set up?
  2. @mcy said in his original PR that the switch to the new Result type might not be able to be done gradually. Any particular reason why that would be?

@mcy
Copy link
Contributor

mcy commented Sep 15, 2021

Am I correct that the advantage of the redactable log macros (info!, error!, etc.) over the base log crate is that the log crate still has some overhead ("an integer load, comparison and jump") even if no logger is set up?

It's not the overhead, but rather being able to compile out the log format messages altogether; it is useful for us to be able to say "if you flip this flag, formatting is redacted at the linker level".

Copy link
Contributor

@mcy mcy left a comment

Choose a reason for hiding this comment

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

This is awesome! Now, the question is... do you want to attempt to migrate the entire crate over to manticore::Result? Unfortunately I think that needs to be done in one shot. =/

We can merge this and do it in a separate CL, or you can give it a shot in this one. I suspect the way you'll wind up doing this is:

  • Replace Result with crate::Result throughout.
  • Add fail, check and cast where necessary until the crate compiles again.

If you can think of a way to do this gradually that would be even more awesome, because then you won't be rebasing over everyone else and I can help you get it done faster.

src/debug.rs Outdated Show resolved Hide resolved
src/debug.rs Outdated Show resolved Hide resolved
src/debug.rs Outdated Show resolved Hide resolved
@moidx moidx removed their request for review October 14, 2021 03:40
@kesyog kesyog force-pushed the kyogeswaran/manticore-debug branch from e1ecb2b to 9be6008 Compare January 5, 2022 23:42
/// impl. We work around this by calling this macro for every Manticore
/// error definition that has `From` impls.
macro_rules! debug_from {
($e:ident<$trait:ident: $bound:path> => $($f:ty),+ $(,)?) => {$(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This first macro rule is an ugly hack so that this macro can be used with Error<Header> in src/server/handler.rs. See usage. It works... but I'm not too proud of it. I'm super new to Rust macros, but based on what I've read, there's not really a clean way of doing this besides resorting to proc macros, which seems like a rabbit hole not worth tackling yet. That said, feedback would be appreciated if you think otherwise.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not really. One option to cut down on repetition is to define something like

macro_rules! debug_from {
  (@actual $e:ident[$($tparams:tt)*] => ...) => {
    // Use `$($tparams)* as appropriate in <>
  };
  ($e:ident => ...) => {debug_from!(@actual $e[] => ...)};
}

Note that wherever a <> is allowed, you can leave it empty, e.g. i32<> is valid Rust. You can use this to your advantage here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I bashed my head against this a bit, but I'm struggling to get any sort of recursive calls to work as I'd expect. For now, I combined two of the macro arms by matching on the tt type.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sg. We can bash on it more later.

@kesyog kesyog requested a review from mcy January 5, 2022 23:57
@kesyog kesyog force-pushed the kyogeswaran/manticore-debug branch from 9be6008 to 682b359 Compare January 10, 2022 03:11
@kesyog kesyog marked this pull request as draft January 11, 2022 00:44
@kesyog
Copy link
Contributor Author

kesyog commented Jan 11, 2022

Hey @mcy, while looking into using the new manticore::Result type everywhere, I think I found a way to switch over to the new fail! and check! macros somewhat incrementally. Check out the latest commit.

The approach is to add a few more From implementations to debug_from! so that the ? Try operator still works everywhere. In order to get it to compile again, I still need to fix a bunch of instances where Err was being returned directly, but otherwise I think it should work.

Let me know what you think. I've moved this PR back to draft status until I fix all the compiler errors.

@kesyog
Copy link
Contributor Author

kesyog commented Jan 11, 2022

I pushed another commit that fixes most of the compiler errors. I highly recommend viewing the individual commits. Assuming this approach is acceptable, the next steps I'm envisioning are:

To do in this PR

  • Figure out an appropriate Result boundary between the x509 modules and the untrusted crate. That crate leaks in a core::result::Result type and it might make sense to simply use that type to reduce the amount of error mapping.
  • Fix remaining few compiler errors
  • Double-check changes, especially wherever the check! was added, to make sure that logical errors weren't introduced.
  • Run and fix unit tests if necessary

Future PR(s)

  • Incrementally add error messages to the fail! macros
  • Incrementally replace usage of the ? operator with the fail! macro so that error messages can be introduced.
  • (maybe) Add filename and line number to the default fail! output this is already provided by the logger
  • (maybe) Replace debug_from! macro with a proc macro. Based on what I've gathered, a proc macro is the way to get around the parsing limitations of declarative macros and more robustly support error types with generic parameters. I'm at the edge of my current level of experience here so I've got no idea how much work this is and whether it's worth doing.

The `debug` module is intended to hold debugging helpers, to make
debugging Manticore tests easier. This will include:

- Redactable logging.
- Error creation capture (e.g., capturing where `Err` variants are
  created).

The generated logs can be captured by tests, and eventually get returned
through Cerberus's "debug log" functionality.

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
This type cannot be created except via special macros in the `debug`
module that generate log statements. We may eventually also attach
extra debugging information to errors, and this type is a good place
to do so.

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>

Fix some syntax and rebase errors
Signed-off-by: Kesavan Yogeswaran <hikes@google.com>
@kesyog kesyog force-pushed the kyogeswaran/manticore-debug branch from 9f5eb23 to 254f201 Compare January 12, 2022 23:19
@kesyog
Copy link
Contributor Author

kesyog commented Jan 12, 2022

After rebasing, I noticed that #148 added a new Error in protocol/spdm/error.rs that has a lifetime parameter to refer to some extra error data. I have to think a bit more on how to handle this. My initial thought is that I'd have to add a lifetime parameter to manticore::Error unless I threw away the extra error data or copied it.

@kesyog
Copy link
Contributor Author

kesyog commented Mar 25, 2022

Some updates:

  • I added some more hackery to debug_from! to handle error types with lifetime specifiers
  • I drew a boundary at the cert/mod.rs level. The parse interface returns the new crate::Result type, but the underlying parsers use the old Result type. This reduces churn and minimizes conflict with the untrusted crate's return types.
  • cargo build succeeds and tests pass! 🎉

@kesyog kesyog marked this pull request as ready for review March 25, 2022 19:33
@kesyog kesyog force-pushed the kyogeswaran/manticore-debug branch from 3b80c21 to 781b2c3 Compare March 25, 2022 19:44
@kesyog
Copy link
Contributor Author

kesyog commented Mar 25, 2022

@mcy this is now ready for review and potential merge. I've held off on squashing in case it helps review, but I'll make sure to squash all the commits prefixed with "SQUASHME." I recommend reading my stream of thoughts above for full context.

Copy link
Contributor

@mcy mcy left a comment

Choose a reason for hiding this comment

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

This is great work. There's a few changes I might suggest but I think those would be better left as follow-ups.

/// impl. We work around this by calling this macro for every Manticore
/// error definition that has `From` impls.
macro_rules! debug_from {
($e:ident<$trait:ident: $bound:path> => $($f:ty),+ $(,)?) => {$(
Copy link
Contributor

Choose a reason for hiding this comment

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

Not really. One option to cut down on repetition is to define something like

macro_rules! debug_from {
  (@actual $e:ident[$($tparams:tt)*] => ...) => {
    // Use `$($tparams)* as appropriate in <>
  };
  ($e:ident => ...) => {debug_from!(@actual $e[] => ...)};
}

Note that wherever a <> is allowed, you can leave it empty, e.g. i32<> is valid Rust. You can use this to your advantage here.

@@ -204,7 +207,7 @@ impl<'arena, A: Arena + ?Sized> ArenaExt<'arena> for &'arena A {
/// arena.reset();
/// let buf3 = arena.alloc_slice::<u8>(64)?;
/// assert_eq!(buf3.len(), 64);
/// # Ok::<(), OutOfMemory>(())
/// # Ok::<(), manticore::Error<OutOfMemory>>(())
Copy link
Contributor

Choose a reason for hiding this comment

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

Personally I actually don't think this is a very useful error: getting an error location from a failed allocation will point inside of arena code, when it would be much more useful for the caller to see the arena call that emitted the error. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

A follow-on task I'm envisioning (and that you incepted me with a few months ago 😄) is to steal ideas from rust-lang/rust#87401: investigate whether we can use #[track_caller] to automatically track the locations of error conversions performed via ?. That'd give extra, more useful debug information and would save the need to add fail! calls in many places.

So my thinking is:

  1. Use the Error type with the Arena trait i.e. no change to current PR state.
  2. If the debug information printed is not useful, callers can still manually add debug info. This is actually already done in some places in src/io/read.rs:
            let out = arena
                .alloc_raw(layout)
                .map_err(|_| fail!(io::Error::BufferExhausted))?;
    Since adding the fallible Arena trait calls are only made Since the Arena trait
  3. Add error conversion tracking using #[track_caller] if possible. If it isn't, rely on step 2.

FWIW switching the Arena trait to using core::result::Result would be pretty easy and I can do that if you do feel strongly that seeing where in arena.rs the error originated would never be useful.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't feel strongly, if you plan on doing stuff with track_caller.

* Replace usage of `Result` with `crate::Result` nearly everywhere. The
  individual certificate parsers use the old `Result` type to avoid
  conflicts with the types returned by the `untrusted` crate, which is
  used for parsing.
* Add some extra `From` implementations to the `debug_from!` macro to
  allow existing usage with the try operator `?`.

Signed-off-by: Kesavan Yogeswaran <hikes@google.com>
@kesyog kesyog force-pushed the kyogeswaran/manticore-debug branch from fde8306 to be80b1a Compare March 29, 2022 01:52
@kesyog
Copy link
Contributor Author

kesyog commented Mar 29, 2022

I've squashed my commits together and this should be good to go now

@kesyog kesyog requested a review from mcy March 29, 2022 02:35
/// impl. We work around this by calling this macro for every Manticore
/// error definition that has `From` impls.
macro_rules! debug_from {
($e:ident<$trait:ident: $bound:path> => $($f:ty),+ $(,)?) => {$(
Copy link
Contributor

Choose a reason for hiding this comment

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

Sg. We can bash on it more later.

@mcy mcy merged commit 8c46384 into lowRISC:master Mar 30, 2022
@kesyog kesyog deleted the kyogeswaran/manticore-debug branch March 30, 2022 17:20
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