From b8e79f3f1057ff91224991f76b3837202bde5a06 Mon Sep 17 00:00:00 2001 From: Kienan Stewart Date: Wed, 7 Feb 2024 15:49:26 -0500 Subject: [PATCH] tests: Handle test failures for ust-constructors with heap allocation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Observed issue ============== A number of tests from `ust/ust-constructor/test_ust_constructor.py` fail when compiled with gcc-4.8 (observed on SLES12SP5). Eg. ``` 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 8 - Found expected event name="tp_a:constructor_c_provider_static_archive" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 10 - Found expected event name="tp_a:constructor_cplusplus_provider_static_archive" msg="global - static archive define and provider" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 11 - Found expected event name="tp:constructor_c_across_units_before_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 12 - Found expected event name="tp:constructor_cplusplus" msg="global - across units before define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 13 - Found expected event name="tp:constructor_c_same_unit_before_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 14 - Found expected event name="tp:constructor_c_same_unit_after_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 15 - Found expected event name="tp:constructor_cplusplus" msg="global - same unit before define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 16 - Found expected event name="tp:constructor_cplusplus" msg="global - same unit after define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 17 - Found expected event name="tp:constructor_c_across_units_after_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 18 - Found expected event name="tp:constructor_cplusplus" msg="global - across units after define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 19 - Found expected event name="tp:constructor_c_same_unit_before_provider" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 20 - Found expected event name="tp:constructor_c_same_unit_after_provider" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 21 - Found expected event name="tp:constructor_cplusplus" msg="global - same unit before provider" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 34 - Found expected event name="tp:destructor_cplusplus" msg="global - same unit before provider" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 35 - Found expected event name="tp:destructor_cplusplus" msg="global - across units after define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 36 - Found expected event name="tp:destructor_cplusplus" msg="global - same unit after define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 37 - Found expected event name="tp:destructor_cplusplus" msg="global - same unit before define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 38 - Found expected event name="tp:destructor_cplusplus" msg="global - across units before define" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 39 - Found expected event name="tp_a:destructor_cplusplus_provider_static_archive" msg="global - static archive define and provider" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 41 - Found expected event name="tp:destructor_c_across_units_after_provider" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 42 - Found expected event name="tp:destructor_c_same_unit_after_provider" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 43 - Found expected event name="tp:destructor_c_same_unit_before_provider" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 44 - Found expected event name="tp:destructor_c_across_units_after_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 45 - Found expected event name="tp:destructor_c_same_unit_after_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 46 - Found expected event name="tp:destructor_c_same_unit_before_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 47 - Found expected event name="tp:destructor_c_across_units_before_define" msg="None" 12:22:17 FAIL: ust/ust-constructor/test_ust_constructor.py 48 - Found expected event name="tp_a:destructor_c_provider_static_archive" msg="None" ``` Cause ===== As gcc-4.8 and earlier don't support C99 compound literals, the lttngust `ust-compiler.h` falls back to using heap allocated compound literals[1][2]. The probe registration in these cases is done via a C++ object[3]. As C-style constructors are executed before the C++ runtime is processed, the probe is not yet registered[4]. In a case where g++ <= 4.8 is being used or `-DLTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP` is defined, the following tracepoints will not be recorded: * C-style constructors and destructors in statically linked archives * C-style constructors and destructors in the application itself * Some C++ constructors and destructors invoked during the initialization of the static global variables * Note: this depends on the initialization order both between translation units, which is not specified, and the initialization order (usually lexicographical) within a given translation unit. This is a known limitation; however, the test does not support verifying that it's being run in a such a situation. Solution ======== A small program has been added which returns a different status code depending on whether `LTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP` is defined or not. The test script uses this application to signal that certain events may fail (in that they may be present, or they may be absent). Drawbacks ========= None. References ========== [1]: https://github.com/lttng/lttng-ust/commit/e1904921db97b70d94e69f0ab3264c6f7fe62f32 [2]: https://github.com/lttng/lttng-ust/commit/7edfc1722684982b9df894c054d69808dc588a6a [3]: https://github.com/lttng/lttng-ust/commit/05bfa3dc3a6e6b2ece3686a5f384b6645c2a5010 [4]: https://github.com/lttng/lttng-ust/blob/3287f48be61ef3491aff0a80b7185ac57b3d8a5d/include/lttng/ust-compiler.h#L110 Change-Id: I49159df4f85126c641aaf5fb0a8b5b22fd91bf12 Signed-off-by: Kienan Stewart Signed-off-by: Jérémie Galarneau --- .gitignore | 1 + .../ust-constructor/test_ust_constructor.py | 152 +++++++++++++++--- .../gen-ust-events-constructor/Makefile.am | 8 +- .../gen-ust-events-constructor/uses_heap.cpp | 16 ++ 4 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 tests/utils/testapp/gen-ust-events-constructor/uses_heap.cpp diff --git a/.gitignore b/.gitignore index eb2873e01..152c2baf8 100644 --- a/.gitignore +++ b/.gitignore @@ -101,6 +101,7 @@ compile_commands.json /tests/regression/tools/filtering/gen-ust-events /tests/utils/testapp/gen-ust-events/gen-ust-events /tests/utils/testapp/gen-ust-events-constructor/gen-ust-events-constructor +/tests/utils/testapp/gen-ust-events-constructor/uses_heap /tests/utils/testapp/gen-ust-events-ns/gen-ust-events-ns /tests/regression/tools/health/health_check /tests/regression/kernel/select_poll_epoll diff --git a/tests/regression/ust/ust-constructor/test_ust_constructor.py b/tests/regression/ust/ust-constructor/test_ust_constructor.py index d7818186c..f4d9cedf0 100755 --- a/tests/regression/ust/ust-constructor/test_ust_constructor.py +++ b/tests/regression/ust/ust-constructor/test_ust_constructor.py @@ -8,6 +8,7 @@ import pathlib import sys import os +import subprocess from typing import Any, Callable, Type """ @@ -25,9 +26,34 @@ sys.path.append(str(test_utils_import_path)) import lttngtest import bt2 +# Determine if LTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP is set. This will +# affect if certain events may or may not be expected when compiling with +# C++. +# @see https://github.com/lttng/lttng-ust/blob/47fa3e4ed7ab43e034dc61fc1480f919f4ee51d0/include/lttng/ust-compiler.h#L51 +# +compound_literal_on_heap = False +process = subprocess.Popen( + [ + os.path.join( + str(test_utils_import_path), + "testapp", + "gen-ust-events-constructor", + "uses_heap", + ) + ] +) +process.wait() +if process.returncode == 0: + compound_literal_on_heap = True + expected_events = [ {"name": "tp_so:constructor_c_provider_shared_library", "msg": None, "count": 0}, - {"name": "tp_a:constructor_c_provider_static_archive", "msg": None, "count": 0}, + { + "name": "tp_a:constructor_c_provider_static_archive", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, { "name": "tp_so:constructor_cplusplus_provider_shared_library", "msg": "global - shared library define and provider", @@ -37,37 +63,73 @@ expected_events = [ "name": "tp_a:constructor_cplusplus_provider_static_archive", "msg": "global - static archive define and provider", "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_across_units_before_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, }, - {"name": "tp:constructor_c_across_units_before_define", "msg": None, "count": 0}, { "name": "tp:constructor_cplusplus", "msg": "global - across units before define", "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_same_unit_before_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_same_unit_after_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, }, - {"name": "tp:constructor_c_same_unit_before_define", "msg": None, "count": 0}, - {"name": "tp:constructor_c_same_unit_after_define", "msg": None, "count": 0}, { "name": "tp:constructor_cplusplus", "msg": "global - same unit before define", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:constructor_cplusplus", "msg": "global - same unit after define", "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_across_units_after_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, }, - {"name": "tp:constructor_c_across_units_after_define", "msg": None, "count": 0}, { "name": "tp:constructor_cplusplus", "msg": "global - across units after define", "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_same_unit_before_provider", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:constructor_c_same_unit_after_provider", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, }, - {"name": "tp:constructor_c_same_unit_before_provider", "msg": None, "count": 0}, - {"name": "tp:constructor_c_same_unit_after_provider", "msg": None, "count": 0}, { "name": "tp:constructor_cplusplus", "msg": "global - same unit before provider", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:constructor_cplusplus", @@ -117,45 +179,91 @@ expected_events = [ "name": "tp:destructor_cplusplus", "msg": "global - same unit before provider", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:destructor_cplusplus", "msg": "global - across units after define", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:destructor_cplusplus", "msg": "global - same unit after define", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:destructor_cplusplus", "msg": "global - same unit before define", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp:destructor_cplusplus", "msg": "global - across units before define", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp_a:destructor_cplusplus_provider_static_archive", "msg": "global - static archive define and provider", "count": 0, + "may_fail": compound_literal_on_heap, }, { "name": "tp_so:destructor_cplusplus_provider_shared_library", "msg": "global - shared library define and provider", "count": 0, }, - {"name": "tp:destructor_c_across_units_after_provider", "msg": None, "count": 0}, - {"name": "tp:destructor_c_same_unit_after_provider", "msg": None, "count": 0}, - {"name": "tp:destructor_c_same_unit_before_provider", "msg": None, "count": 0}, - {"name": "tp:destructor_c_across_units_after_define", "msg": None, "count": 0}, - {"name": "tp:destructor_c_same_unit_after_define", "msg": None, "count": 0}, - {"name": "tp:destructor_c_same_unit_before_define", "msg": None, "count": 0}, - {"name": "tp:destructor_c_across_units_before_define", "msg": None, "count": 0}, - {"name": "tp_a:destructor_c_provider_static_archive", "msg": None, "count": 0}, + { + "name": "tp:destructor_c_across_units_after_provider", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_same_unit_after_provider", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_same_unit_before_provider", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_across_units_after_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_same_unit_after_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_same_unit_before_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp:destructor_c_across_units_before_define", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, + { + "name": "tp_a:destructor_c_provider_static_archive", + "msg": None, + "count": 0, + "may_fail": compound_literal_on_heap, + }, {"name": "tp_so:destructor_c_provider_shared_library", "msg": None, "count": 0}, ] @@ -244,12 +352,16 @@ def validate_trace(trace_location, tap): ) for event in expected_events: - tap.test( - event["count"] == 1, - 'Found expected event name="{}" msg="{}"'.format( - event["name"], str(event["msg"]) + may_fail = "may_fail" in event.keys() and event["may_fail"] + if not may_fail: + tap.test( + event["count"] == 1, + 'Found expected event name="{}" msg="{}"'.format( + event["name"], str(event["msg"]) + ), ), - ) + else: + tap.skip("Event '{}' may or may not be recorded".format(event["name"])) tap.test(unknown_event_count == 0, "Found no unexpected events") diff --git a/tests/utils/testapp/gen-ust-events-constructor/Makefile.am b/tests/utils/testapp/gen-ust-events-constructor/Makefile.am index 4e7e1e102..b323baee2 100644 --- a/tests/utils/testapp/gen-ust-events-constructor/Makefile.am +++ b/tests/utils/testapp/gen-ust-events-constructor/Makefile.am @@ -48,9 +48,9 @@ libtp_a_define_la_SOURCES = \ tp-a-define.cpp \ tp-a.h -noinst_PROGRAMS = gen-ust-events-constructor -gen_ust_events_constructor_SOURCES = \ - main.cpp \ +noinst_PROGRAMS = gen-ust-events-constructor \ + uses_heap +gen_ust_events_constructor_SOURCES = main.cpp \ 01-tp-before-define.cpp \ 02-define-tp.cpp \ 03-tp-after-define.cpp \ @@ -66,4 +66,6 @@ gen_ust_events_constructor_LDADD = $(UST_LIBS) \ $(builddir)/libtp-a-provider.la \ $(top_builddir)/tests/utils/libtestutils.la \ $(DL_LIBS) + +uses_heap_SOURCES = uses_heap.cpp endif diff --git a/tests/utils/testapp/gen-ust-events-constructor/uses_heap.cpp b/tests/utils/testapp/gen-ust-events-constructor/uses_heap.cpp new file mode 100644 index 000000000..35933deb0 --- /dev/null +++ b/tests/utils/testapp/gen-ust-events-constructor/uses_heap.cpp @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Kienan Stewart + * + * SPDX-License-Identifier: LGPL-2.1-only + */ + +#include + +int main() +{ +#ifdef LTTNG_UST_ALLOCATE_COMPOUND_LITERAL_ON_HEAP + return 0; +#else + return 1; +#endif +} -- 2.34.1