How can I use cmake to test processes that are expected to fail with an exception? (e.g., failures due to clang's address sanitizer) - cmake

I've got some tests that test that clang's address sanitizer catch particular errors. (I want to ensure my understanding of the types of error it can catch is correct, and that future versions continue to catch the type of errors I'm expecting them to.) This means I have several tests that fail by crapping out with an OTHER_FAULT, which appears to be the fixed way that clang's runtime reports an error.
I've set the WILL_FAIL flag to TRUE for these tests, but this only seems to check the return value from a successful, exception-free failure. If the process terminates with an exception, cmake still classes it as a failure.
I've also tried using PASS_REGULAR_EXPRESSION to watch for the distinguishing messages that are printed out when this error occurs, but again, cmake seems to class the test as a failure if it terminates with an exception.
Is there anything I can do to get around this?
(clang-specific answers are also an option! - but I doubt this will be the last time I need to test something like this, so I'd prefer to know how to do it with cmake generally, if it's possible)

CTest provides only basic, commonly used interpretators for result of test programs. For implement other interpretators you can write simple program/script, which wraps the test and interpret its result as needed. E.g. C program (for Linux):
test_that_crash.c:
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main(int argc, char** argv)
{
pid_t pid = fork();
if(pid == -1)
{
// fork fails
return 1;
}
else if(pid)
{
// Parent - wait child and interpret its result
int status = 0;
wait(&status);
if(WIFSIGNALED(status)) return 0; // Signal-terminated means success
else return 1;
}
else
{
// Child - execute wrapped command
execvp(argv[1], argv + 1);
exit(1);
}
}
This program can be used in CMake as follows:
CMakeLists.txt:
# Compile our wrapper
add_executable(test_that_crash test_that_crash.c)
# Similar to add_test(name command), but test is assumed successfull only if it is crashed(signalled)
macro(add_test_crashed name command)
# Use generic flow of add_test() command for automatically recognize our executable target
add_test(NAME ${name} COMMAND test_that_crash ${command} ${ARGN})
endmacro(add_test_crashed)
# ...
# Add some test, which should crash
add_test_crashed(clang.crash.1 <clang-executable> <clang-args>)

There is also a clang-specific solution: configure its manner of exit using the ASAN_OPTIONS environment variable. (See https://github.com/google/sanitizers/wiki/AddressSanitizerFlags.) To do this, set the ASAN_OPTIONS environment variable to abort_on_error=0. When the address sanitizer detects a problem, the process will then do _exit(1) rather than (presumably) abort(), and will thus appear to have terminated cleanly. You can then pick this up using cmake's WILL_FAIL mechanism. (It's still not clear why OS X and Linux differ in this respect - but there you go.)
As a bonus, the test fails much more quickly.
(Another handy option that can improve turnaround time when running through cmake is to set ASAN_SYMBOLIZER_PATH to an empty value, which stops the address sanitizer symbolizing the stack traces. Symbolizing takes a moment, but there's no point doing it when running through cmake, since you can't see the output.)
Rather than do this by hand, I made a Python script that sets the environment appropriately on OS X (doing nothing on Linux), and invokes the test. I then add each asan test using a macro, along the lines of Tsyvarev's answer.
macro(add_asan_test basename)
add_executable(${basename} ${basename}.c)
add_test(NAME test/${basename} COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/wrap_clang_sanitizer_test.py -a $<TARGET_FILE:${basename}>)
set_tests_properties(test/${basename} PROPERTIES WILL_FAIL TRUE)
endmacro()
This gives a simple pass/fail as quickly as possible. I'm in the habit of investigating failures by running the test in question from the shell by hand and examining the output, in which case I get the stack trace as normal (and the fact exiting by abort is a bit slow is less of a problem).
(There are similar options for the other sanitizers, but I haven't investigated them.)

Related

How can I define an executable that has different compiler command-line arguments?

I have a C++ project and I want to test the compatibility of library headers with different compiler versions. I have a simple source file (that includes said headers) and I want to change the compiler argument to std=gnu++11 for this one target. How do I do that?
executable('old_compiler_test', ['octest.cxx']
# override ARGS here ??? how
)
Note that I have
add_global_arguments(
['-std=gnu++17',
....
rather than the dedicated option for this, in spite of the warning to prefer the special option, because the special option simply doesn't work. (Why is a question I've never tracked down)
update
To clarify: I'm not trying to make additional configurations in the same way that debug and release are configurations. I want a different compiler argument to be applied to a single target within the configuration.
From the Meson documentation, you can use the argument <languagename>_args to pass additional compiler arguments. In your case, since you use C++, it would give something like
executable('old_compiler_test', ['octest.cxx'],
cpp_args: ['std=gnu++11']
)
However the documentation also specify that there are no way to disable an argument added by add_global_argument(), so you will end up with both -std=gnu++17 and -std=gnu++11 passed to the compiler. I don't know how your compiler will behave, but I tried to pass both arguments to GCC 10.2 and it uses c++17 (not what you want).
Workaround
It seems that if you define the C++ version in the project() statement, Meson will removes it if an other version is specified in compiler arguments, giving the behaviour you expect.
Here is the sample I used:
meson.build
project('project-name', 'cpp',
default_options: ['cpp_std=c++17']
)
executable('old_compiler_test', ['octest.cxx'],
cpp_args: ['-std=gnu++11']
)
octest.cxx
#include <iostream>
int main() {
std::cout << __cplusplus << std::endl;
}
After compilation, running the executable will print 201103, which means that the compiler used c++11 as desired.

ctest won't output stdout from printf if test fails

In a quite simple test-case, the output of printf() is not shown, if the test fails. I use µunit as a framework and the test routine itself is trivial:
static MunitResult test(...)
{
// Some variable initialisation
printf("Test running...\n");
//Do the test
bool bResult = tested_method();
munit_assert(bResult == true);
}
If I comment out the assertion, i.e. the test succeeds, the printf-output is shown. It isn't if the test fails. Running other test routines works as expected and shows their output from printf() correctly.
I invoke ctest like this to run the test:
ctest -V --output-on-failure -R '.*nameoftest.*'
The whole is running inside a docker container on Windows 10.
How can I make ctest display all output the test-routine sends on stdout?
Thanks for your help and have a nice day!
The solution, in my case, was, to call the generated elf-executable directly, and not via ctest. It seems that ctest adds another layer of output-redirection which I wasn't able to circumvent. By calling the binary directly, I could get all the output and logs I desired.
This is not a direct solution to the problem, but a workaround I found acceptable.

How can a CMake variable be hidden?

I have a CMake project which lets a globally set variable (set with -DARDUINO_SDK_PATH=/a/b/c on command line) disappear i.e. suddenly the given value is gone which leads to a fatal error.
I know there are different ways to "hide" a variable (e.g. inside functions or external projects)
In my case:
the variable is not being set explicitly anywhere in the code (e.g. via set() or find_path())
the access which leads to the error is on top level (i.e. not inside a function)
there are instructions (i.e. same file/line) where in one case the variable has the value it's been given and the next time it's gone
Tracing the variable with variable_watch(ARDUINO_SDK_PATH) I can see that everything works fine before the compiler is being checked:
cmake -DARDUINO_SDK_PATH=/a/b/c <path>
...
... everything fine, ${DARDUINO_SDK_PATH} == '/a/b/c' everywhere
...
-- Check for working C compiler: /usr/bin/avr-gcc
...
... here the variable is empty and not being traced any more
...
Here is my suggestion:
Does the compiler check (indicated by check for working C compiler .. on the terminal) have it's own variable space and does not know variables provided on command line?
Note: This question is a generalization of this question, which has become way too specialized but might offer some useful background information.
That any modification to variable is not traced after the variable_watch() command seems like a bug somewhere in CMake to me.
Generally speaking a "cached CMake variable" can be hidden by a "normal CMake variable" with the same name. But e.g. find_path() won't run again or modify a variable if already set.
Here is an example:
cmake_minimum_required(VERSION 2.4)
project(VariableWatchTest NONE)
variable_watch(MY_TEST_VAR)
set(MY_TEST_VAR "something" CACHE INTERNAL "")
message("${MY_TEST_VAR}")
set(MY_TEST_VAR "hiding something")
message("${MY_TEST_VAR}")
unset(MY_TEST_VAR)
message("${MY_TEST_VAR}")
find_path(MY_TEST_VAR NAMES "CMakeLists.txt" HINTS "${CMAKE_CURRENT_LIST_DIR}")
message("${MY_TEST_VAR}")
Would give (without the variable_watch() messages:
-- something
-- hiding something
-- something
-- something
References
What's the CMake syntax to set and use variables?
I'm not sure whether this is a bug or a feature but (at least some) CMake variables are not available in certain steps of the CMake configuration procedure.
You can check this by adding something like this to your toolchain file:
MESSAGE("FOO: ${FOO}")
and run CMake like this
cd build-dir
cmake -DFOO=TEST ..
You will likely see FOO printed with value TEST once in the beginning of the configuration process and later printed again but being empty.
Just don't access variables from the global space inside a toolchain file (doesn't belong there anyway).

Determining symbol addresses using binutils/readelf

I am working on a project where our verification test scripts need to locate symbol addresses within the build of software being tested. This might be used for setting breakpoints or reading static data from memory. What I am after is to create a map file containing symbol names, base address in memory, and size. Our build outputs an ELF file which has the information I want. I've been trying to use the readelf, nm, and objdump tools to try and to gain the symbol addresses I need.
I originally tried readelf -s file.elf and that seemed to access some symbols, particularly those which were written in assembler. However, many of the symbols that I wanted were not in there - specifically those that originated within our Ada code.
I used readelf --debug-dump file.elf to dump all debug information. From that I do see all symbols, including those that were in the Ada code. However, the format seems to be in the DWARF format. Does anyone know why these symbols would not be output by readelf when I ask it to list the symbolic information? Perhaps there is simply an option I am missing.
Now I could go to the trouble of writing a custom DWARF parser to get the information but if I can get it using one of the Binutils (nm, readelf, objdump) then I'd really like prefer a standard solution.
DWARF is the debug information and tries to reflect the relation of the original source code. Taking following code as an example
static int one() {
// something
return 1;
}
int main(int ac, char **av) {
return one();
}
After you compile it using gcc -O3 -g, the static function one will be inlined into main. So when you use readelf -s, you will never see the symbol one. However, when you use readelf --debug-dump, you can see one is a function which is inlined.
So, in this example, compiler does not prohibit you use optimization with -g, so you can still debug the executable. In that example, even the function is optimized and inlined, gdb still can use DWARF information to know the function and source/line from current code block inside inlined function.
Above is just a case of compiler optimization. There might be plenty of reasons that could lead to mismatch symbols address between readelf -s and DWARF.

Can GNU make execute a rule whenever an error occurs?

This is slightly different from Can a Makefile execute code ONLY when an error has occurred?.
I'd like a rule or special target that is made whenever an error occurs (independent of the given target; without changing the rule for every target as the other answer seems to imply with the || operator).
In dmake there is special target .ERROR that is executed whenever an error condition is detected. Is there a similar thing with GNU make?
(I'm still using GNU make 3.81, but I didn't find anything in the documentation of the new GNU make 4.0 either)
Gnu doesn't support it explicitly, but there's ways to hack almost anything. Make returns 1 if any of the makes fail. This means that you could, on the command line, rerun make with your error rule if the first make failed:
make || make error_targ
Of course, I'll assume you just want to put the added complexity within the makefile itself. If this is the case, you can create a recursive make file:
all:
$(MAKE) normal_targ || $(MAKE) error_targ
normal_targ:
... normal make rules ...
error_targ:
... other make rules ...
This will cause the makefile to try to build normal_targ, and iff it fails, it will run error_targ. It makes it a bit harder to read the makefile for the inexperienced, but it puts all the logic in one place.