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

Win32, Reporter: Access violation causes assert(!m_sectionStack.empty()); #1967

Open
suratovvlad opened this issue Jun 25, 2020 · 4 comments

Comments

@suratovvlad
Copy link

suratovvlad commented Jun 25, 2020

Describe the bug
There is a possible problem with the RunContext::handleFatalErrorCondition( StringRef message ) function.
When on the Access violation exception happens in the some code, this function is called from the
FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo).

During the processing fatal error, first handler calls the handleUnfinishedSections(); function, which cleans internal member m_sectionStack.
After that it calls m_reporter->sectionEnded(testCaseSectionStats); where the assert(!m_sectionStack.empty()) exists, which terminates application.

This situation happens, if I execute the test with the JUnit reporter.

Expected behavior
Handling of fatal error should not break internal Catch2 stuff and the reporting abilities.

Reproduction steps
I could not yet build the repeatable simple example for triggering the Access Violation, but the code with test looks like that:

TEST_CASE("Name of test case")
{
   // here is an initialization of some complex object
   GIVEN("Given")
   {
        WHEN("When")
        {
            THEN("Then")
            {
                REQUIRE(/*some not failing check*/);
            }
        }
   }
   // Here initilized object is destructed, and during this destruction the Access Violation exception happens
} 

Platform information:

  • OS: Windows NT
  • Compiler+version: Microsoft (R) C/C++ Optimizing Compiler Version 19.24.28314
  • Catch version: v2.11.2

Additional context
No yet

@suratovvlad
Copy link
Author

I was able to create a code to reproduce the issue. Latest version 2.12.3 is affected as well.

NDEGUB is undefined to have asserts in the release mode.
This code should be compiled in release mode with "/EHa" compiler option to enable structured exception handling.
Such options are close to what we have in our build system.
After compilation, execution should be done as test.exe -r junit

#undef NDEBUG
#include <assert.h>

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include <windows.h>
#include <iostream>

class Example
{
public:

	~Example()
	{
		std::cout << "destructed" << std::endl;
	}

};

int filterException(int code, PEXCEPTION_POINTERS ex)
{
	std::cout << "Filtering " << std::hex << code << std::endl;
	return EXCEPTION_EXECUTE_HANDLER;
}

void testProcessorFault()
{
	Example e;
	int* p = 0;
	*p = 42;
}

struct Simple
{
	~Simple()
	{
		__try
		{
			testProcessorFault();
		}
		__except (filterException(GetExceptionCode(), GetExceptionInformation()))
		{
			std::cout << "caught" << std::endl;
		}
	}

};

TEST_CASE("Failing reporter"){

	Simple a;
	GIVEN("Given")
	{
		WHEN("When 1")
		{
			THEN("Then 1")
			{
				SUCCEED();
			}
		}
		WHEN("When 2")
		{
			THEN("Then 2")
			{
				SUCCEED();
				REQUIRE(1 == 1);
			}
		}
	}
}

int main(int argc, char* argv[])
{
	return Catch::Session().run(argc, argv);
}

This is the output I have with Catch 2.12.3, and these similar results I have on my Jenkins.

PS C:\Users\VSuratov\source\repos\CMakeProject1\out\build\x86-Release\CMakeProject1> .\CMakeProject1.exe -r junit
<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite errors="0" failures="1" tests="2" hostname="tbd" time="0.000295" timestamp="2020-07-02T17:02:26Z">
    <testcase classname="CMakeProject1.exe.global" name="Failing reporter" time="0.0" status="run">
      <error message="{Unknown expression after the reported line}">
FAILED:
  {Unknown expression after the reported line}
SIGSEGV - Segmentation violation signal
at ..\..\..\CMakeProject1\CMakeProject1.cpp(59)
      </error>
    </testcase>
    <testcase classname="CMakeProject1.exe.global" name="Failing reporter/Given: Given/When: When 1/Then: Then 1" time="0.000019" status="run"/>
    <system-out/>
    <system-err/>
  </testsuite>
</testsuites>Assertion failed: !m_sectionStack.empty(), file C:\Users\VSuratov\source\repos\CMakeProject1\CMakeProject1\catch.hpp, line 5909

@suratovvlad
Copy link
Author

The thing is that in our case the access violation exception happens randomly, and we could not avoid this, because for better optimization we use Intel tbb malloc library. It seems it is not well written, and sometimes it dereferences the null pointer in its internal stuff, but it has SEH handling with __try and __except, so, such dereferencing does not affect our applications in any bad way.

Since Catch2 has VEH handling, it catches this exception in the first place (because VEH is prioritized over SEH), and tries to handle such fault. While handling, the m_sectionStack is cleared, and when reporting is enabled, code inside m_reporter->sectionEnded asserts.

I found special define CATCH_CONFIG_NO_WINDOWS_SEH that disables internal handling in the Catch2.
Probably this is only a solution that could be applied for our case, but I believe, Catch2 should more carefully handle fatal error, and allow correct reporting.

@trrwilson
Copy link
Contributor

This can be reproduced very trivially (on Windows, at least) with a test case like this one:

TEST_CASE("divide by zero") {
  int zero{ 0 };
  int oops = 1 / zero;
}

This will unwind through the fatal exception code path but then ultimately barf when trying to pop an already-empty stack.

It's not a complete fix, but simply adding a !m_sectionStack.empty() check before calling pop_back() lets the teardown happen enough for a well-formed result file.

@helmesjo
Copy link

helmesjo commented Feb 22, 2021

Any progress on this one? Still seeing sporadic failures on our CI, and it would be nice with something more descriptive being printed. (:

ImmanuelHaffner added a commit to mutable-org/mutable that referenced this issue Apr 27, 2023
The `unittest` binary crashes with
```
unittest: /var/lib/gitlab-runner/builds/yS6csq8A/0/bigdata/mutable/mutable/third-party/catch2/include/catch2/catch.hpp:5918: virtual void Catch::CumulativeReporterBase<Catch::JunitReporter>::testCaseEnded(const Catch::TestCaseStats &) [DerivedT = Catch::JunitReporter]: Assertion `m_sectionStack.size() == 0' failed.
```
This error seems to be related to the Catch 2 JUnit reporter.  See
catchorg/Catch2#1801 and
catchorg/Catch2#1967.

To remedy this problem, we simply don't use produce a report anymore.
It was never used, anyway.
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

No branches or pull requests

3 participants