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

Testscript reports "stack buffer overrun" when an exception is thrown. #51

Closed
Klaim opened this issue Sep 13, 2019 · 4 comments

Comments

@Klaim
Copy link

commented Sep 13, 2019

Context

> b --version
build2 0.12.0-a.0.7c426821e7fb
libbutl 0.12.0-a.0.69ed8e0c82e4
host x86_64-microsoft-win32-msvc14.2
Copyright (c) 2014-2019 Code Synthesis Ltd
This is free software released under the MIT license.

How To Reproduce

  1. bdep new someapp && cd someapp
  2. In someapp/someapp.cxx add the following line at the beginning of main():
    throw std::runtime_error("some error");
  3. b test

Observed

PS C:\...\someapp> b test
c++ someapp\cxx{someapp}
ld someapp\exe{someapp}
test someapp\testscript{testscript} someapp\exe{someapp}
someapp\testscript:3:1: error: someapp\someapp.exe terminated abnormally: stack buffer overrun
  info: test id: basics
  info: while testing someapp\exe{someapp}
  info: while testing dir{someapp\}
  info: while testing dir{.\}
someapp\testscript:7:1: error: someapp\someapp.exe terminated abnormally: stack buffer overrun
  info: test id: missing-name
  info: while testing someapp\exe{someapp}
  info: while testing dir{someapp\}
  info: while testing dir{.\}
info: failed to test dir{.\}

Expected

Not a stack buffer overrun report. (the "terminated abnormally" part is correct in this repro case).

Notes

  • It is not clear that the stack buffer overrun comes from build2/testscript, so it kind of lead me to first think the issue was in the program being tested.
  • In the case I first saw this issue, the program is interractive:
    • One test expects an exception to be thrown, then switch back to waiting for input - this one works (the exception is thrown and the test pass as expected);
    • Another test expects the same operation to not fail (so it should not pass - it was a work in progress) - this one fails with "stack buffer overrun";
  • That last point is surprising because if you run the same executable manually, the exception is logged but the program does not crash because it was catched (it gets back to waiting for the next input). The "stack bufferoverrun" only appear when running through testscript, even if the exception is catched (and logged through cerr).
    This might suggest an issue in the handling of cerr output stream?
@karen-arutyunov

This comment has been minimized.

Copy link
Member

commented Sep 13, 2019

The program in your example aborts due to unhanded exception. The testscript implementation obtains the program exit code with GetExitCodeProcess() call that ends up with 0xC0000409 (STATUS_STACK_BUFFER_OVERRUN).

Agree this is weird but not sure what we can do about it.

@Klaim

This comment has been minimized.

Copy link
Author

commented Sep 13, 2019

Interesting... and weird. I'll try to find some other cases where I had to do some child process handling (on Windows) but I don't remember this specific return value for cases of exception escaping main(). I wonder if that behavior is from more recent VS versions.

I just did some research and found this: https://devblogs.microsoft.com/oldnewthing/20190108-00/?p=100655

What this means is that nowadays when you get a STATUS_STACK_BUFFER_OVERRUN, it doesn’t actually mean that there is a stack buffer overrun. It just means that the application decided to terminate itself with great haste.

then

From the above list, the interesting one for me is the FAST_FAIL_FATAL_APP_EXIT code. This code is used when the C runtime function abort() gets called. And abort() is called by std::terminate(). And std::terminate() is called automatically for things like throwing an exception out of a noexcept function, or if a thrown exception goes unhandled.

While this explains the issue, it is not clear to me if there is a way to distinguish fast failures from real stack buffer overruns once you get that return value. Or does this mean that it is always an exception caught? (that would explain the other stack buffer overrun issues I saw that were fixed in build2, that were indeed due to unhandled exceptions boris told me)

The information is confirmed in the doc for the __fastfail() intrinsic : https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail?view=vs-2019

I'll investigate more see if there is a way to differentiate the errors.

@Klaim

This comment has been minimized.

Copy link
Author

commented Sep 13, 2019

I checked with boost::process see if they managed to get a clearer error but nope, same return value.

I'm not sure what to do about this, maybe some kind of documentation pointing here or on the links I found would help ...

Or maybe adding a note in the error report that it might not be a buffer overrun (on this specific platform)?

Anyway ok now the whole thing makes sense.

@boris-kolpackov

This comment has been minimized.

Copy link
Member

commented Sep 28, 2019

Thanks for doing the research. Based on that we've now changed the error message to a more accurate "Aborted".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
3 participants
You can’t perform that action at this time.