Commit e306f3e3 authored by Milian Wolff's avatar Milian Wolff
Browse files

Disable asan sigaltstack for select clang unit tests

Apparently LLVM's internal sigaltstack usage does not play well
together with the sanitizers, see [1]. This leads to failed tests
on our CI. Setting use_sigaltstack=0 as an ASAN_OPTION fixes this
issue, which this patch here does.

Sadly, we have to jump through some hoops to achieve this though.
On one hand, we want to extend the ASAN_OPTIONS, not overwrite it.
As such, we can't just set the ctest ENVIRONMENT property, as the
CI sets a bunch of custom flags in the ASAN_OPTIONS env var. Users
might have their own set of values there too. Once we can rely on
CMake 3.22 or newer, we might use ENVIRONMENT_MODIFICATION.

Furthermore, I could not get __asan_default_options() to work
with GCC.

So, instead for now we use some dirty hackery: We check whether the
use_sigaltstack option is set in ASAN_OPTIONS. If not, we set it
explicitly to 0 and then execve the test anew. This way we can be
sure that the environment gets picked up properly.

[1]: https://github.com/google/sanitizers/issues/849
parent 01a35a3e
......@@ -11,4 +11,6 @@ export LSAN_OPTIONS=print_suppressions=0,suppressions=$kdev_source_dir/lsan.supp
export UBSAN_OPTIONS=print_stacktrace=1,suppressions=$kdev_source_dir/ubsan.supp
export ASAN_OPTIONS=detect_stack_use_after_return=1
# there seems to be a funky clash with sigaltstack usage in llvm, so disable it for the sanitizers
# see also: https://github.com/google/sanitizers/issues/849
export ASAN_OPTIONS=detect_stack_use_after_return=1,use_sigaltstack=0
......@@ -13,6 +13,9 @@ target_link_libraries(clang-parser
KDevClangPrivate
)
add_library(sanitizer_test_init STATIC sanitizer_test_init.cpp)
target_link_libraries(sanitizer_test_init PRIVATE Qt5::Core)
add_library(codecompletiontestbase STATIC codecompletiontestbase.cpp)
target_link_libraries(codecompletiontestbase PUBLIC
KDev::Tests
......@@ -39,6 +42,7 @@ ecm_add_test(test_codecompletion.cpp
TEST_NAME test_codecompletion
LINK_LIBRARIES
codecompletiontestbase
sanitizer_test_init
)
ecm_add_test(test_assistants.cpp
......@@ -47,6 +51,7 @@ ecm_add_test(test_assistants.cpp
KDev::Tests
Qt5::Test
KDevClangPrivate
sanitizer_test_init
)
ecm_add_test(test_clangutils.cpp
......
/*
SPDX-FileCopyrightText: 2022 Milian Wolff <mail@milianw.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#include "sanitizer_test_init.h"
#include <QString>
#include <QtGlobal>
#if defined(Q_OS_UNIX)
#include <unistd.h>
#endif
namespace KDevelop
{
namespace
{
/**
* LLVM and ASAN don't play well together, see [1].
* We have to disable sigaltstack or we crash.
* The code below detects whether we need to disable this option.
* If yes, we change the environment and re-execute ourselves with the new
* environment. Sadly, it doesn't seem to work to use __asan_default_options
* for this purpose here...
*
* [1]: https://github.com/google/sanitizers/issues/849
*/
[[maybe_unused]] void setupAsan(char** argv)
{
auto asanOptions = qEnvironmentVariable("ASAN_OPTIONS");
if (asanOptions.contains(QLatin1String("use_sigaltstack"))) {
return; // nothing to do
}
asanOptions += QLatin1String(",use_sigaltstack=0");
qputenv("ASAN_OPTIONS", asanOptions.toUtf8());
execv(argv[0], argv);
}
}
void sanitizerTestInit([[maybe_unused]] char** argv)
{
#if defined(Q_OS_UNIX)
// gcc
#if defined(__SANITIZE_ADDRESS__)
setupAsan(argv);
return;
#endif
// clang
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
setupAsan(argv);
return;
#endif
#endif
#endif
}
}
/*
SPDX-FileCopyrightText: 2022 Milian Wolff <mail@milianw.de>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
*/
#ifndef KDEVELOP_SANITIZER_TEST_INIT
#define KDEVELOP_SANITIZER_TEST_INIT
namespace KDevelop
{
void sanitizerTestInit(char** argv);
}
#endif // KDEVELOP_SANITIZER_TEST_INIT
......@@ -43,10 +43,16 @@
#include <clang-c/Index.h>
#include "sanitizer_test_init.h"
using namespace KDevelop;
using namespace KTextEditor;
QTEST_MAIN(TestAssistants)
int main(int argc, char** argv)
{
KDevelop::sanitizerTestInit(argv);
QTEST_MAIN_IMPL(TestAssistants)
}
ForegroundLock *globalTestLock = nullptr;
StaticAssistantsManager *staticAssistantsManager() { return Core::self()->languageController()->staticAssistantsManager(); }
......
......@@ -30,6 +30,8 @@
#include "codecompletion/includepathcompletioncontext.h"
#include "../clangsettings/clangsettingsmanager.h"
#include "sanitizer_test_init.h"
#include <KTextEditor/Editor>
#include <KTextEditor/Document>
#include <KTextEditor/View>
......@@ -39,7 +41,11 @@
#include <QVersionNumber>
#include <QStandardPaths>
QTEST_MAIN(TestCodeCompletion)
int main(int argc, char** argv)
{
KDevelop::sanitizerTestInit(argv);
QTEST_MAIN_IMPL(TestCodeCompletion)
}
static const auto NoMacroOrBuiltin = ClangCodeCompletionContext::ContextFilters(
ClangCodeCompletionContext::NoBuiltins | ClangCodeCompletionContext::NoMacros);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment