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

test-signalhandler: test SIGFPE / assert exitcodes #7238

Merged
merged 2 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions test/signal/test-signalhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,24 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef _GNU_SOURCE
#define _GNU_SOURCE // required to have feenableexcept()
#endif

#include "config.h"

#if defined(USE_UNIX_SIGNAL_HANDLING)
#include "signalhandler.h"

#include <cassert>
#include <cfenv>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#if !defined(__APPLE__)
#include <cfenv>
#endif

// static functions are omitted from trace

/*static*/ NORETURN void my_assert() // NOLINT(misc-use-internal-linkage)
Expand All @@ -45,15 +52,17 @@
++*(int*)nullptr;
}

/*static*/ void my_fpe() // NOLINT(misc-use-internal-linkage)
{
#if !defined(__APPLE__)
feenableexcept(FE_ALL_EXCEPT); // TODO: check result
#endif
std::feraiseexcept(FE_UNDERFLOW | FE_DIVBYZERO); // TODO: check result
// TODO: to generate this via code
/*static*/ int my_fpe() // NOLINT(misc-use-internal-linkage)
{
if (feenableexcept(FE_ALL_EXCEPT) == -1)
return 2;
if (std::feraiseexcept(FE_ALL_EXCEPT) != 0)
return 3;
return 1 % -1;
Copy link
Owner

Choose a reason for hiding this comment

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

I imagine that 1 % -1 is always 0, isn't it? why not write 0 here? Because it's testcode?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That is the invalid floating-point operation which is causing the exception. The code above is just telling it to raise the exception and to trap it (cause the signal).

https://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html

}
#endif
#endif

int main(int argc, const char * const argv[])
{
Expand All @@ -67,10 +76,12 @@ int main(int argc, const char * const argv[])
my_assert();
else if (strcmp(argv[1], "abort") == 0)
my_abort();
else if (strcmp(argv[1], "fpe") == 0)
my_fpe();
else if (strcmp(argv[1], "segv") == 0)
my_segv();
#if !defined(__APPLE__)
else if (strcmp(argv[1], "fpe") == 0)
return my_fpe();
#endif

return 0;
#else
Expand Down
27 changes: 15 additions & 12 deletions test/signal/test-signalhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,54 +32,57 @@ def __call_process(arg):


def test_assert():
_, stdout, stderr = __call_process('assert')
exitcode, stdout, stderr = __call_process('assert')
if sys.platform == "darwin":
assert stderr.startswith("Assertion failed: (false), function my_assert, file test-signalhandler.cpp, line "), stderr
else:
assert stderr.endswith("test-signalhandler.cpp:34: void my_assert(): Assertion `false' failed.\n"), stderr
assert stderr.endswith("test-signalhandler.cpp:41: void my_assert(): Assertion `false' failed.\n"), stderr
lines = stdout.splitlines()
assert lines[0] == 'Internal error: cppcheck received signal SIGABRT - abort or assertion'
# no stacktrace of MacOs
# no stacktrace of macOS
if sys.platform != "darwin":
assert lines[1] == 'Callstack:'
assert lines[2].endswith('my_abort()'), lines[2] # TODO: wrong function
assert lines[len(lines)-1] == 'Please report this to the cppcheck developers!'
assert exitcode == -6


def test_abort():
_, stdout, _ = __call_process('abort')
exitcode, stdout, _ = __call_process('abort')
lines = stdout.splitlines()
assert lines[0] == 'Internal error: cppcheck received signal SIGABRT - abort or assertion'
# no stacktrace on MaCos
# no stacktrace on macOS
if sys.platform != "darwin":
assert lines[1] == 'Callstack:'
assert lines[2].endswith('my_segv()'), lines[2] # TODO: wrong function
assert lines[len(lines)-1] == 'Please report this to the cppcheck developers!'
assert exitcode == -6


def test_segv():
_, stdout, stderr = __call_process('segv')
exitcode, stdout, stderr = __call_process('segv')
assert stderr == ''
lines = stdout.splitlines()
if sys.platform == "darwin":
assert lines[0] == 'Internal error: cppcheck received signal SIGSEGV - SEGV_MAPERR (at 0x0).'
else:
assert lines[0] == 'Internal error: cppcheck received signal SIGSEGV - SEGV_MAPERR (reading at 0x0).'
# no stacktrace on MacOS
# no stacktrace on macOS
if sys.platform != "darwin":
assert lines[1] == 'Callstack:'
assert lines[2].endswith('my_segv()'), lines[2] # TODO: wrong function
assert lines[len(lines)-1] == 'Please report this to the cppcheck developers!'
assert exitcode == -11


# TODO: make this work
@pytest.mark.skip
@pytest.mark.skipif(sys.platform == 'darwin', reason='Cannot raise FPE on macOS')
def test_fpe():
_, stdout, stderr = __call_process('fpe')
exitcode, stdout, stderr = __call_process('fpe')
assert stderr == ''
lines = stdout.splitlines()
assert lines[0].startswith('Internal error: cppcheck received signal SIGFPE - FPE_FLTDIV (at 0x7f'), lines[0]
assert lines[0].startswith('Internal error: cppcheck received signal SIGFPE - FPE_FLTINV (at 0x'), lines[0]
assert lines[0].endswith(').'), lines[0]
assert lines[1] == 'Callstack:'
assert lines[2].endswith('my_fpe()'), lines[2]
assert lines[3].endswith('my_fpe()'), lines[2]
assert lines[len(lines)-1] == 'Please report this to the cppcheck developers!'
assert exitcode == -8
Loading