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

Ignore return of SymInitializeW on Windows #231

Merged
merged 1 commit into from
Jul 31, 2019

Conversation

alexcrichton
Copy link
Member

This commit updates the behavior of backtraces on Windows to execute
SymInitializeW globally once-per-process and ignore the return value
as to whether it succeeded or not. This undoes previous work in this
crate to specifically check the return value, and this is a behavior
update for the standard library when this goes into the standard
library.

The SymInitializeW function is required to be called on MSVC before
any backtraces can be captured or before any addresses can be
symbolized. This function is quite slow. It can only be called
once-per-process and there's a corresponding SymCleanup to undo the
work of SymInitializeW.

The behavior of what to do with SymInitializeW has changed a lot over
time in this crate. The very first implementation for Windows paired
with SymCleanup. Then reports of slowness at rust-lang/rustup#591
led to ac8c6d2 where SymCleanup was removed. This led to #165 where
because the standard library still checked SymInitializeW's return
value and called SymCleanup generating a backtrace with this crate
would break RUST_BACKTRACE=1. Finally (and expectedly) the performance
report has come back as #229 for this crate.

I'm proposing that the final nail is put in this coffin at this point
where this crate will ignore the return value of SymInitializeW,
initializing symbols once per process globally. This update will go into
the standard library and get updated on the stable channel eventually,
meaning both libstd and this crate will be able to work with one another
and only initialize the process's symbols once globally. This does mean
that there will be a period of "breakage" where we will continue to make
RUST_BACKTRACE=1 not useful if this crate is used on MSVC, but that's
sort of the extension of the status quo as of a month or so ago. This
will eventually be fixed once the stable channel of Rust is updated.

This commit updates the behavior of backtraces on Windows to execute
`SymInitializeW` globally once-per-process and ignore the return value
as to whether it succeeded or not. This undoes previous work in this
crate to specifically check the return value, and this is a behavior
update for the standard library when this goes into the standard
library.

The `SymInitializeW` function is required to be called on MSVC before
any backtraces can be captured or before any addresses can be
symbolized. This function is quite slow. It can only be called
once-per-process and there's a corresponding `SymCleanup` to undo the
work of `SymInitializeW`.

The behavior of what to do with `SymInitializeW` has changed a lot over
time in this crate. The very first implementation for Windows paired
with `SymCleanup`. Then reports of slowness at rust-lang/rustup#591
led to ac8c6d2 where `SymCleanup` was removed. This led to #165 where
because the standard library still checked `SymInitializeW`'s return
value and called `SymCleanup` generating a backtrace with this crate
would break `RUST_BACKTRACE=1`. Finally (and expectedly) the performance
report has come back as #229 for this crate.

I'm proposing that the final nail is put in this coffin at this point
where this crate will ignore the return value of `SymInitializeW`,
initializing symbols once per process globally. This update will go into
the standard library and get updated on the stable channel eventually,
meaning both libstd and this crate will be able to work with one another
and only initialize the process's symbols once globally. This does mean
that there will be a period of "breakage" where we will continue to make
`RUST_BACKTRACE=1` not useful if this crate is used on MSVC, but that's
sort of the extension of the status quo as of a month or so ago. This
will eventually be fixed once the stable channel of Rust is updated.
@alexcrichton
Copy link
Member Author

@sfackler mind taking a look at this and lending your opinion to this? This will be a behavior change for the standard library on MSVC, so I figured it's good to double check with at least one other libs member to ensure it's ok.

@sfackler
Copy link
Member

Under what conditions does SymInitializeW fail? Being called when initialized?

@alexcrichton
Copy link
Member Author

Unfortunately that's not 100% clear to me. I know for certain of one failure case, but I don't know of others.

The for-certain failure case is that if you call SymInitializeW twice in a row it will fail the second time with "error invalid parameter". This is because it can only be called if symbols aren't initialized (or if they were previously torn down by SymCleanup).

Presumably we could also detect cases of like "actual symbol initialization failed" and ignore the "you initialized twice" errors and actually report "symbol initialization failed" failures, but I don't currently know of a way to do so.

I believe there are also not really any consequences for using symbolication/backtrace functions if SymInitialize fails for a legitimate reason. I think you just get weird and/or truncated results.

@sfackler
Copy link
Member

Ok, and this is going to regress the standard library since it expects SymInitializeW to succeed before taking each backtrace? It might make sense to backport a backtrace upgrade to beta in that case.

@alexcrichton
Copy link
Member Author

It sort of depends on how you look at it. The standard library has always behaved as it does today, which is to pair initialize/cleanup calls and skip generating a backtrace if initialization fails. This crate itself was changed a month or so ago to also pair initialize/cleanup calls to enusre that if you use this crate RUST_BACKTRACE still works.

In that sense the standard library if you don't use this crate doesn't change, it just continues to work. The libstd from January will be as "broken" as the libstd when this PR hits crates.io for the backtrace crate. Pairing backtrace from crates.io now with libstd from June (ish) works today, but after this PR hits crates.io it'll go back to the January state of not working.

I would classify this more as a temporary regression for this crate than for the standard library myself.

@sfackler
Copy link
Member

Maybe someday we'll just be able to use Gimli :P

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