Why is Google Test segfaulting? - c++

I'm new to Google Test and I'm playing around with the provided examples. My issue is, when I introduce a failure and set GTEST_BREAK_ON_FAILURE=1 (or use the command line option), GTest will segfault.
I am considering this example. If I insert something like this into any of the tests, I will start to get the segfault:
EXPECT_EQ(8, 2*3);
Just to reiterate, that is only when I have also set GTEST_BREAK_ON_FAILURE=1. I have run from the command line and also with gdb. If that environment variable is not set, it reports the error but does not segfault.
Any clue to what could be causing this/what I am doing wrong? I've been looking for a similar issue, but I haven't run into anything yet.
FYI I am using Google Test version 1.7.0 running on 64 bit CrunchBang Linux 11 "Waldorf".
edit code sample:
// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
Debugger output:
(gdb) run
Starting program: /home/yourfavoriteprotein/bin/cpp_unit_test_frameworks/gtest-1.7.0/samples/mytest
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Running main() from test_main.cc
[==========] Running 6 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN ] FactorialTest.Negative
[ OK ] FactorialTest.Negative (0 ms)
[ RUN ] FactorialTest.Zero
[ OK ] FactorialTest.Zero (0 ms)
[ RUN ] FactorialTest.Positive
sample1_unittest.cc:112: Failure
Value of: 2*3
Actual: 6
Expected: 8
Program received signal SIGSEGV, Segmentation fault.
0x0000000000413427 in testing::UnitTest::AddTestPartResult(testing::TestPartResult::Type, char const*, int, std::string const&, std::string const&) ()
(gdb) quit

GTEST_BREAK_ON_FAILURE=1 means that Google Test drops you into the debugger if a test fails.
It so happens that an easy, portable way to drop you into the debugger is to trigger a segfault.
In other words, this behavior is by design; Google Test deliberately triggers a segfault to make the debugger run. (See here in the Google Test code.)

Related

bazel test lacking SEGFAULT information

We are currently migrating from a CMake-based build to bazel. For unit-testing, we are using our own implemented framework.
When dealing with a SEGFAULT, ctest gives the following output:
The following tests FAILED:
19 - SomeTest (SEGFAULT)
Errors while running CTest
However, when executing the exact same test with the exact same build-options and sources, the bazel output looks like:
//services/SomeTest:test FAILED in 0.2s
/root/.cache/bazel/_bazel_root/b343aed36e4de4757a8e698762574e37/execroot/repo/bazel-out/k8-fastbuild/testlogs/SomeTest/test/test.log
The other output is just the regular printout from the test, nothing regarding the SEGFAULT. Same goes for the contents of SomeTest/test/test.log.
I tried the following options to bazel test: --test_output=all, --test_output=errors, --verbose_test_summary, and --verbose_failures.
What am I missing here?
The output you're seeing comes from CTest, not from your application under test. If you want to see helpful information like that you'll need some testing framework to provide it to you. Here's a comparison between a vanilla test and a Catch2 test.
Setup
test_vanilla.cc
int main() { return 1 / 0; }
test_catch2.cc
#include <catch2/catch.hpp>
TEST_CASE("Hello") { REQUIRE(1 / 0); }
WORKSPACE
load("#bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "catch2",
sha256 = "3cdb4138a072e4c0290034fe22d9f0a80d3bcfb8d7a8a5c49ad75d3a5da24fae",
strip_prefix = "Catch2-2.13.7",
urls = ["https://github.com/catchorg/Catch2/archive/v2.13.7.tar.gz"],
)
BUILD
cc_test(
name = "test_vanilla",
srcs = ["test_vanilla.cc"],
)
cc_test(
name = "test_catch2",
srcs = ["test_catch2.cc"],
defines = ["CATCH_CONFIG_MAIN"],
deps = ["#catch2"],
)
Testing
No test framework
Now let's run the tests.
❯ bazel test //:test_vanilla
[...]
//:test_vanilla FAILED in 0.3s
test.log
exec ${PAGER:-/usr/bin/less} "$0" || exit 1
Executing tests from //:test_vanilla
-----------------------------------------------------------------------------
You can see that the test failed, because it did not return 0 (as it failed by illegally dividing by zero.
If you have systemd-coredump installed (and coredumps enabled), you can get some info with
❯ coredumpctl -1 debug
[...]
Core was generated by `/home/laurenz/.cache/bazel/_bazel_laurenz/be59967ad4f5a83f16e874b5d49a28d5/sand'.
Program terminated with signal SIGFPE, Arithmetic exception.
#0 0x0000561398132668 in main ()
(gdb)
Catch2
If you have a test framework like CTest or Catch2, it will provide more infos so you don't even need to check the coredump yourself. The test log will provide the problematic file and line as well as the signal.
❯ bazel test //:test_catch2
[...]
//:test_catch2 FAILED in 0.2s
test.log
exec ${PAGER:-/usr/bin/less} "$0" || exit 1
Executing tests from //:test_catch2
-----------------------------------------------------------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test_catch2 is a Catch v2.13.7 host application.
Run with -? for options
-------------------------------------------------------------------------------
Hello
-------------------------------------------------------------------------------
test_catch2.cc:3
...............................................................................
test_catch2.cc:3: FAILED:
due to a fatal error condition:
SIGFPE - Floating point error signal
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed

Boost Unit Test start but not execute

I wrote some simple boost tests.
The test compiles, but starting it does not execute the test body.
Below is an example of a test.
// Windows uses Boost static libraries
#ifndef _WIN32
#define BOOST_TEST_DYN_LINK
#endif
#define BOOST_TEST_MODULE "SimpleTest"
#include <boost/test/unit_test.hpp>
#include "radarInterface/ObjConfiguration.h"
#include "radarInterface/ObjIF.h"
#include "CommonFunctions.h"
#ifndef BOOST_TEST
#define BOOST_TEST(A)
#endif
BOOST_AUTO_TEST_SUITE(_obj_interface_)
BOOST_AUTO_TEST_CASE(init_string)
{
BOOST_TEST_MESSAGE("init_string");
ObjConfiguration conf;
conf.mcastAddress("225.0.0.40");
conf.mcastPort(6310);
conf.ipAddress("127.0.0.1");
conf.tcpPort(6312);
BOOST_TEST(conf.isComplete() == true);
ObjIF objIf;
BOOST_CHECK_NO_THROW(objIf.init(conf));
usleep(3000000);
ri.fini();
}
BOOST_AUTO_TEST_SUITE_END()
Trying to run it looks like everything is fine but in truth the test body is not running.
I use CMake to compile and run tests.
The following is the result of running the tests with CMake (ctest) after their compilation.
Test project C:/Users/kongrosian/SimpleTest/build
Start 1: ObjInterface_test
1/1 Test #1: ObjInterface_test .............. Passed 0.03 sec
100% tests passed, 0 tests failed out of 1
Total Test time (real) = 0.05 sec
Even running it from the command line doesn't seem to work. Using the command
".\ObjInterface_test.exe --log_level=message --run_test=init_string"
I would expect to see at least the "init string" message. Instead I simply get
Process PID: xxxx
If I use the test code written in the comments by sehe in my project the result is the same.
When executing commands
./sotest --log_level=message --run_test=_obj_interface_/init_string
or
./sotest --list_content
I get Process PID: xxxx as command line output.
Do you have any ideas on why this behavior?
The boost version I'm using is 1.72.
I hope I have clarified better.
It's unclear how you arrive at the conclusion the test is not running. It would seem it explicitly states that it is running the test (and passing).
However, the time consumed doesn't match your expectation, which leads to the guess that you may be running the wrong target (an old build e.g. one of a build configuration that is not up-to-date).
Command Line
Given the test suite name, the command line argument should be like:
./sotest --log_level=message --run_test=_obj_interface_/init_string
Which for me prints:
Running 1 test case...
init_string
*** No errors detected
You can use some wildcards if you want:
./sotest -l all -t "*/init_string"
Running 1 test case...
Entering test module "SimpleTest"
/home/sehe/Projects/stackoverflow/test.cpp(20): Entering test suite "_obj_interface_"
/home/sehe/Projects/stackoverflow/test.cpp(22): Entering test case "init_string"
init_string
/home/sehe/Projects/stackoverflow/test.cpp(45): info: check conf.isComplete() == true has passed
/home/sehe/Projects/stackoverflow/test.cpp(53): info: check &apos;no exceptions thrown by objIf.init(conf)&apos; has passed
/home/sehe/Projects/stackoverflow/test.cpp(22): Leaving test case "init_string"; testing time: 3000212us
/home/sehe/Projects/stackoverflow/test.cpp(20): Leaving test suite "_obj_interface_"; testing time: 3000270us
Leaving test module "SimpleTest"; testing time: 3000294us
*** No errors detected
Use --list_content to ... list the contents:
 sehe  ~  Projects  stackoverflow  ./sotest --list_content
_obj_interface_*
init_string*
Warning About Naming
Names starting with underscores (or containing double __ underscores) are reserved. Using them makes your program not well-formed and you may run into issues. See What are the rules about using an underscore in a C++ identifier?
So you should probably change the name of your test suite.

Rust tests fail to even run

I'm writing a project to learn how to use Rust and I'm calling my project future-finance-labs. After writing some basic functions and verifying the app can be built I wanted to include some tests, located in aggregates/mod.rs. [The tests are in the same file as the actual code as per the documentation.] I'm unable to get the tests to run despite following the documentation to the best of my ability. I have tried to build the project using PowerShell as well as Bash. [It fails to run on Fedora Linux as well]
Here is my output on Bash:
~/future-finance-labs$ cargo test -- src/formatters/mod.rs
Finished test [unoptimized + debuginfo] target(s) in 5.98s
Running target/debug/deps/future_finance_labs-16ed066e1ea3b9a1
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Using PowerShell I get the same output with some errors like the following:
error: failed to remove C:\Users\jhale\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\home\jhale\future-finance-labs\target\debug\build\mime_guess-890328c8763afc22\build_script_build-890328c8763afc22.build_script_build.c22di3i8-cgu.0.rcgu.o: The system cannot find the path specified. (os error 3)
After my initial excitement at the prospect of writing a few tests that passed on the first attempt, I quickly realized all the green was indicative; rather, of a failure to even run the tests. I just want to run the unit tests. Running cargo test alone without a separate and file fails as well. Why can't I run any test in this project with my current setup?
It can't find your test because the rust compiler doesn't know about it. You need to add mod aggregates to main.
mod aggregates;
fn main() {
println!("Hello, world!");
}
After you do that, you'll see that your aggregates/mod.rs doesn't compile for many reasons.
And as Mihir was trying to say, you need to use the name of the test, not the name of the file to run a specific test:
cargo test min_works
cargo test aggregates
See also:
How do I “use” or import a local Rust file?
Rust Book: Controlling How Tests Are Run

How should I go about debugging a SIGFPE in a large, unfamiliar software project?

I'm trying to get to the bottom of a bug in KDE 5.6. The locker screen breaks no matter how I lock it. Here's the relevant code: https://github.com/KDE/kscreenlocker/blob/master/abstractlocker.cpp#L51
When I run /usr/lib/kscreenlocker_greet --testing, I get an output of:
KCrash: Application 'kscreenlocker_greet' crashing...
Floating point exception (core dumped)
I'm trying to run it with gdb to try and pin the exact location of the bug, but I'm not sure where to set the breakpoints in order to isolate the bug. Should I be looking for calls to KCrash? Or perhaps a raise() call? Can I get gdb to print off the relevant line of code that causes SIGFPE?
Thanks for any advice you can offer.
but I'm not sure where to set the breakpoints in order to isolate the bug
You shouldn't need to set any breakpoints at all: when a process running under GDB encounters a fatal signal (such as SIGFPE), the OS notices that the process is being traced by the debugger, and notifies the debugger (instead of terminating the process). That in turn causes GDB to stop, and prompt you for additional commands. It is at that time that you can look around and understand what caused the crash.
Example:
cat -n t.c
1 #include <fenv.h>
2
3 int foo(double d) {
4 return 1/d;
5 }
6
7 int main()
8 {
9 feenableexcept(FE_DIVBYZERO);
10 return foo(0);
11 }
gcc -g t.c -lm
./a.out
Floating point exception
gdb -q ./a.out
(gdb) run
Starting program: /tmp/a.out
Program received signal SIGFPE, Arithmetic exception.
0x000000000040060e in foo (d=0) at t.c:4
4 return 1/d;
(gdb) bt
#0 0x000000000040060e in foo (d=0) at t.c:4
#1 0x0000000000400635 in main () at t.c:10
(gdb) q
Here, as you can see, GDB stops when SIGFPE is delivered, and allows you to look around and understand the crash.
In your case, you would want to first install debuginfo symbols for KDE, and then run
gdb --args /usr/lib/kscreenlocker_greet --testing
(gdb) run

Jenkins and Google Test (death test) using fork()

we use Jenkins and Google Test for our project.
I wrote a GTest death test (EXPECT_EXIT) for our code.
It forks the code which is tested and captures its return code.
My tested code either terminates with signal 6 or with exit code 0.
Running the test on my local machine works out fine, it captures the code correctly.
Jenkins on the other hand probably does not fork()? The unit test terminates with signal 6 and the build fails.
Any ideas how this problem can be solved?