Snaipe / Criterion

A cross-platform C and C++ unit testing framework for the 21st century
MIT License
1.95k stars 177 forks source link

failed to override main function on Ubuntu 22.04 #495

Open kyet opened 1 year ago

kyet commented 1 year ago

Hi. I installed criterion via apt on Ubuntu 22.04. (libcriterion-dev, version: 2.4.0-rc-18-g1cc3911-1) In order to support custom arguments, I added the main function according to the below manual.

https://criterion.readthedocs.io/en/master/internal.html

Then the following error appeared.

labuser@openstack1:~/criterion-test$ cat main.c
#include <criterion/criterion.h>

Test(foo, bar) { }

int main(int argc, char *argv[]) {
    struct criterion_test_set *tests = criterion_initialize();

    int result = 0;
    if (criterion_handle_args(argc, argv, true))
        result = !criterion_run_all_tests(tests);

    criterion_finalize(tests);
    return result;
}
labuser@openstack1:~/criterion-test$ gcc -lcriterion -o main main.c
labuser@openstack1:~/criterion-test$ ./main
criterion: Re-entering criterion from a test worker. This is a catastrophic bug, please report it on the issue tracker.
Bailing out to avoid fork-bombing the system.
criterion: Could not spawn test instance: Protocol error
Aborted (core dumped)

As you probably remember, the error message has been added in the issue below.

If my understanding is correct, in normal operation, boxfort manipulates the main function I added, and when the main function is executed again through fork & execve, the bxfi_exec function should be called by the manipulation.

However, it seems that boxfort manipulated the wrong main function (the main function inside the criterion), and due to this, when the main function is executed, the criterion_run_all_tests function is executed again and an error message is output as an exception handling to prevent falling into an infinite loop.

I'm not familiar with the internals of criterion and boxfort, so you can disregard my assumptions.

Strangely, there is no problem with the package downloaded from github.com (here) and the package I built myself. To experiment with different packages, I used LD_LIBRARY_PATH as in the example below.

# using apt package -> ERROR
LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu ./main

# using compiled package (g1cc3911 version) -> OK
LD_LIBRARY_PATH=/usr/local/lib/x86_64-linux-gnu ./main

# using downloaded package -> all OK
LD_LIBRARY_PATH=$HOME/ws/criterion-2.4.0-rc-18-g1cc3911/lib ./main
LD_LIBRARY_PATH=$HOME/ws/criterion-2.4.0-rc-12-g4cccb18/lib ./main
LD_LIBRARY_PATH=$HOME/ws/criterion-2.4.0/lib ./main
LD_LIBRARY_PATH=$HOME/ws/criterion-2.4.1/lib ./main

So I thought it was not a version issue. I tried compiling using clang instead of gcc as shown below, but there is still no problem with the package I built myself.

meson setup --wipe build
env CC=clang meson build
ninja -C build
sudo ninja -C build install

I wonder if you can reproduce it too. I've experimented with multiple servers. Thank you for your hard work!

MrAnno commented 1 year ago

Hi @kyet,

Thanks for reporting this issue. I've reproduced the same using the official Ubuntu package.

So far I don't see what causes it, perhaps a hardening compiler flag.

Note: On Debian "testing", v2.4.1-2 works as expected, but the same version does not work on Ubuntu 23.04.

MrAnno commented 1 year ago

Yep, this is caused by the -Wl,-Bsymbolic-functions linker flag, which is used in Ubuntu builds.

https://launchpadlibrarian.net/649780170/buildlog_ubuntu-lunar-amd64.criterion_2.4.1-2_BUILDING.txt.gz

MrAnno commented 1 year ago

I've submitted a bug report: https://bugs.launchpad.net/ubuntu/+source/criterion/+bug/2018156