diff --git a/External/CheckerGccPlugins/CMakeLists.txt b/External/CheckerGccPlugins/CMakeLists.txt index 37eccb20e194297d788f4893e7956806e2160fef..9ff789ba9cae9664abf6e69042f726d34cc26c5a 100644 --- a/External/CheckerGccPlugins/CMakeLists.txt +++ b/External/CheckerGccPlugins/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration # The name of the package: atlas_subdir( CheckerGccPlugins ) @@ -46,7 +46,11 @@ function( CheckerGccPlugins_test1 testName mode ) cmake_parse_arguments( ARG "" "ENVIRONMENT" "" ${ARGN} ) set( _fullName ${testName}_${mode} ) - set( _checkerTestFlags ${CMAKE_CXX_FLAGS_${mode}} ) + if( "${mode}" STREQUAL "LTO" ) + set( _checkerTestFlags "${CMAKE_CXX_FLAGS_RELEASE} -flto " ) + else() + set( _checkerTestFlags ${CMAKE_CXX_FLAGS_${mode}} ) + endif() configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test/checker_test.sh.in ${CMAKE_CURRENT_BINARY_DIR}/CheckerGccPlugins_${_fullName}.sh @ONLY ) @@ -62,6 +66,7 @@ endfunction( CheckerGccPlugins_test1 ) function( CheckerGccPlugins_test testName ) CheckerGccPlugins_test1( ${testName} RELEASE ${ARGN} ) CheckerGccPlugins_test1( ${testName} DEBUG ${ARGN} ) +CheckerGccPlugins_test1( ${testName} LTO ${ARGN} ) endfunction( CheckerGccPlugins_test ) @@ -111,3 +116,21 @@ CheckerGccPlugins_test( thread10 ENVIRONMENT CHECKERGCCPLUGINS_CONFIG=${CMAKE_CU CheckerGccPlugins_test( thread16 ENVIRONMENT CHECKERGCCPLUGINS_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/share/test_unchecked.config ) CheckerGccPlugins_test( config ENVIRONMENT CHECKERGCCPLUGINS_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/share/test.config ) CheckerGccPlugins_test( check_ts2 ENVIRONMENT CHECKERGCCPLUGINS_CONFIG=${CMAKE_CURRENT_SOURCE_DIR}/share/test.config ) + + +function( CheckerGccPlugins_ltolink_test ) + set( testName "ltolink" ) + set( _checkerTestFlags "${CMAKE_CXX_FLAGS_RELEASE} -flto " ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/test/checker_ltolink_test.sh.in + ${CMAKE_CURRENT_BINARY_DIR}/CheckerGccPlugins_ltolink.sh + @ONLY ) + atlas_add_test( ltolink + SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/CheckerGccPlugins_ltolink.sh + ENVIRONMENT ${ARG_ENVIRONMENT} + POST_EXEC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/test/post.sh ltolink '' ${CMAKE_CURRENT_SOURCE_DIR}/share/ltolink_test.ref" + ) +endfunction( CheckerGccPlugins_ltolink_test ) + +CheckerGccPlugins_ltolink_test() + + diff --git a/External/CheckerGccPlugins/share/ltolink_test.ref b/External/CheckerGccPlugins/share/ltolink_test.ref new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/External/CheckerGccPlugins/src/callcheck_plugin.cxx b/External/CheckerGccPlugins/src/callcheck_plugin.cxx index 3df23ca66cf57f71a58fa6283acf6977c13f9da2..dc85352f0d3b81f0db4e569e8d40b2a2b2829d03 100644 --- a/External/CheckerGccPlugins/src/callcheck_plugin.cxx +++ b/External/CheckerGccPlugins/src/callcheck_plugin.cxx @@ -4,7 +4,7 @@ * @date Apr, 2019 * @brief Various ATLAS-specific function call checks. * - * Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ @@ -36,6 +36,7 @@ #include "stringpool.h" #include "attribs.h" #include "gcc-rich-location.h" +#include "feshim.h" #include <vector> #include <unordered_map> #include <string> @@ -343,7 +344,7 @@ unsigned int callcheck_pass::callcheck_execute (function* fun) if (!fndecl) { fndecl = vcall_fndecl (stmt); } - std::string name = decl_as_string (fndecl, TFF_SCOPE + TFF_TEMPLATE_NAME); + std::string name = CheckerGccPlugins::decl_as_string (fndecl, TFF_SCOPE + TFF_TEMPLATE_NAME); hide_targs (name); std::string::size_type ipos = name.find (" [with"); if (ipos != std::string::npos) { diff --git a/External/CheckerGccPlugins/src/check_thread_safety_p.cxx b/External/CheckerGccPlugins/src/check_thread_safety_p.cxx index 4a739609e44680c57c3515ce60bee73dadaca43b..a952a14395a1ab29cca3cd155337a39840d3b970 100644 --- a/External/CheckerGccPlugins/src/check_thread_safety_p.cxx +++ b/External/CheckerGccPlugins/src/check_thread_safety_p.cxx @@ -16,7 +16,7 @@ * If a decl has the attribute check_thread_safety_debug, then a diagnostic * will be printed saying if that decl has thread-safety checking enabled. * - * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ @@ -395,7 +395,8 @@ bool check_thread_safety_location_p (location_t loc) return false; } - std::string file = LOCATION_FILE(loc); + const char* s = LOCATION_FILE(loc); + std::string file = s ? s : ""; thread_safe_files_t::iterator it = thread_safe_files.find (file); if (it != thread_safe_files.end()) return it->second; diff --git a/External/CheckerGccPlugins/src/checker_gccplugins.cxx b/External/CheckerGccPlugins/src/checker_gccplugins.cxx index 30ceea8b66ebc966701c61b2375d6878e75e89ed..e217f04095f9c4b7ae5333adce5e9fa977336c2a 100644 --- a/External/CheckerGccPlugins/src/checker_gccplugins.cxx +++ b/External/CheckerGccPlugins/src/checker_gccplugins.cxx @@ -4,7 +4,7 @@ * @date Aug, 2014 * @brief Framework for running checker plugins in gcc. * - * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ @@ -20,11 +20,13 @@ #include "tree-core.h" #include "tree-pass.h" #include "plugin.h" -#include "c-family/c-pragma.h" #include "tree.h" #include "cp/cp-tree.h" #include "diagnostic.h" #include "gimple.h" +#include "stringpool.h" +#include "attribs.h" +#include "feshim.h" /* Declare GPL compatible license. */ @@ -174,7 +176,7 @@ checker_plugin_info = { # define ATTRIB(A) {A, 0, 0, false, false, false, false, nullptr, nullptr} -static struct +static const struct attribute_spec attribs[] = { ATTRIB("thread_safe"), @@ -184,8 +186,16 @@ attribute_spec attribs[] = ATTRIB("argument_not_const_thread_safe"), ATTRIB("check_thread_safety"), ATTRIB("check_thread_safety_debug"), +#if GCC_VERSION < 14000 ATTRIB(nullptr), +#endif + }; +#if GCC_VERSION >= 14000 +static const scoped_attribute_specs attrib_table = + { + "ATLAS", attribs }; +#endif #undef ATTRIB @@ -194,7 +204,12 @@ void register_checker_attributes (void* /*event_data*/, void* /*data*/) { //fprintf (stderr, "register_attributes %s\n", thread_safe_attr.name); - register_scoped_attributes (attribs, "ATLAS" + register_scoped_attributes ( +#if GCC_VERSION >= 14000 + attrib_table +#else + attribs, "ATLAS" +#endif #if GCC_VERSION >= 12000 , false #endif @@ -206,12 +221,14 @@ static void register_checker_pragmas (void* /*event_data*/, void* /*data*/) { + using CheckerGccPlugins::c_register_pragma; c_register_pragma ("ATLAS", "check_thread_safety", CheckerGccPlugins::handle_check_thread_safety_pragma); c_register_pragma ("ATLAS", "no_check_thread_safety", CheckerGccPlugins::handle_no_check_thread_safety_pragma); - cpp_define (parse_in, "ATLAS_GCC_CHECKERS"); + using CheckerGccPlugins::cpp_define; + cpp_define ("ATLAS_GCC_CHECKERS"); } @@ -231,6 +248,8 @@ plugin_init(struct plugin_name_args *plugin_info, return 1; } + if (!CheckerGccPlugins::init_shims()) return 0; + // Handle command-line arguments. if (collect_plugin_args(plugin_info)!=0) return 1; @@ -279,7 +298,13 @@ CheckerConfig config; void inform_url (location_t loc, const char* url) { - if (!in_system_header_at(loc) && !global_dc->dc_warn_system_headers) + if (!in_system_header_at(loc) && +#if GCC_VERSION < 14000 + !global_dc->dc_warn_system_headers +#else + !global_dc->m_warn_system_headers +#endif + ) inform (loc, "See %s.", url); } @@ -343,7 +368,8 @@ tree vcall_fndecl (gimplePtr stmt) // collide with what we're looking for. Just ignore such entries. // But careful: Can't just compare the types, because TYP // may be a const type. - TYPE_NAME (strip_typedefs (typ)) == TYPE_NAME (strip_typedefs (CP_DECL_CONTEXT (*it))) + TYPE_NAME (CheckerGccPlugins::strip_typedefs (typ)) == + TYPE_NAME (CheckerGccPlugins::strip_typedefs (CP_DECL_CONTEXT (*it))) ) { tree fn_ndx_tree = DECL_VINDEX (*it); diff --git a/External/CheckerGccPlugins/src/divcheck_plugin.cxx b/External/CheckerGccPlugins/src/divcheck_plugin.cxx index e1de8202c1993c8bb992eaefa46cf7414c064015..21a7071438ff67d372758a1c487f81a0605c6263 100644 --- a/External/CheckerGccPlugins/src/divcheck_plugin.cxx +++ b/External/CheckerGccPlugins/src/divcheck_plugin.cxx @@ -4,7 +4,7 @@ * @date May, 2015 * @brief Check for redundant divisions. * - * Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration */ @@ -53,11 +53,7 @@ const pass_data divcheck_pass_data = { GIMPLE_PASS, /* type */ "divcheck", /* name */ -#if GCC_VERSION < 9000 - 0, /* optinfo_flags */ -#else OPTGROUP_NONE, /* optinfo_flags */ -#endif TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ diff --git a/External/CheckerGccPlugins/src/feshim.cxx b/External/CheckerGccPlugins/src/feshim.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1031de1b3ed498c0c64b4dfa006a742c44ede7c4 --- /dev/null +++ b/External/CheckerGccPlugins/src/feshim.cxx @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CheckerGccPlugins/src/feshim.cxx + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2024 + * @brief Shims for accessing front-end symbols. + */ + +#define FESHIM_CXX +#define scope_chain dum_scope_chain +#include "checker_gccplugins.h" +#include "tree.h" +#include "cp/cp-tree.h" +#include "feshim.h" +#include <dlfcn.h> +#undef scope_chain + +// Shim variables. +tree cp_global_trees[CPTI_MAX]; +cpp_reader* parse_in = nullptr; + + +namespace CheckerGccPlugins +{ + + +//******************************************************************** +// The shim functions. +// These will bounce the calls to the real_* pointers which +// we retrieved in init_shims(). + + +typedef void (*c_register_pragma_t) (const char* space, + const char* type, + pragma_handler_1arg handler); +c_register_pragma_t real_c_register_pragma = nullptr; + + +void c_register_pragma (const char *space, const char *name, + pragma_handler_1arg handler) +{ + (*real_c_register_pragma) (space, name, handler); +} + + +//******** + + +typedef void (*cpp_define_t) (cpp_reader *, const char *); +cpp_define_t real_cpp_define = nullptr; +void cpp_define (const char* def) +{ + (*real_cpp_define) (parse_in, def); +} + + +//******** + + +typedef tree (*strip_typedefs_t) (tree t, bool* remove_attributes, unsigned int flags); +strip_typedefs_t real_strip_typedefs = nullptr; +tree strip_typedefs (tree t, bool* remove_attributes, unsigned int flags) +{ + return (*real_strip_typedefs) (t, remove_attributes, flags); +} + + +//******** + + +typedef tree (*lookup_base_t) (tree t, tree base, /*base_access*/int access, + /*base_kind*/int *kind_ptr, + /*tsubst_flags_t*/int complain +#if GCC_VERSION >= 14000 + , HOST_WIDE_INT offset +#endif + ); +lookup_base_t real_lookup_base = nullptr; +tree lookup_base (tree t, tree base) +{ + return (*real_lookup_base) (t, base, + 0, // ba_any + NULL, + 0 // tf_none +#if GCC_VERSION >= 14000 + , -1 +#endif + ); +} + + +//******** + + +typedef const char* (*type_as_string_t) (tree t, int flags); +type_as_string_t real_type_as_string = nullptr; +const char* type_as_string (tree t, int flags) +{ + return (*real_type_as_string) (t, flags); +} + + +//******** + + +typedef const char* (*decl_as_string_t) (tree t, int flags); +decl_as_string_t real_decl_as_string = nullptr; +const char* decl_as_string (tree t, int flags) +{ + return (*real_decl_as_string) (t, flags); +} + + +//******** + + +typedef tree (*skip_artificial_parms_for_t) (const_tree fn, tree list); +skip_artificial_parms_for_t real_skip_artificial_parms_for = nullptr; +tree skip_artificial_parms_for (const_tree fn, tree list) +{ + return (*real_skip_artificial_parms_for) (fn, list); +} + + +//******** + + +typedef tree (*dfs_walk_all_t) (tree binfo, tree (*pre_fn) (tree, void *), + tree (*post_fn) (tree, void *), void *data); +dfs_walk_all_t real_dfs_walk_all = nullptr; +tree +dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *), + tree (*post_fn) (tree, void *), void *data) +{ + return (*real_dfs_walk_all) (binfo, pre_fn, post_fn, data); +} + + +//******** + + +typedef int (*cp_type_quals_t) (const_tree t); +cp_type_quals_t real_cp_type_quals = nullptr; +int cp_type_quals (const_tree t) +{ + return (*real_cp_type_quals) (t); +} + + +//******** + + +typedef tree (*look_for_overrides_here_t) (tree type, tree fndecl); +look_for_overrides_here_t real_look_for_overrides_here = nullptr; +tree look_for_overrides_here (tree type, tree fndecl) +{ + return (*real_look_for_overrides_here) (type, fndecl); +} + + +//******************************************************************** +// Shim for getting the current namespace. + + +saved_scope** scope_chain_ptr = nullptr; +tree get_current_namespace() +{ + return (*scope_chain_ptr)->old_namespace; +} + + +//******************************************************************** + + +bool init_shims() +{ + // Handle referencing the main program. + void* handle = dlopen (NULL, 0); + + // Check to see if any FE symbols are present. + // If not, exit gracefully and disable the checkers. + if (!dlsym (handle, "scope_chain")) { + return false; + } + + // Helper for looking up a symbol. + // Abort if we don't find the symbol. + auto findsym = [&] (auto& fn, const char* sym) + { + void* p = dlsym (handle, sym); + if (!p) { + fatal_error (input_location, "CheckerGccPlugins: cannot find symbol %<%s%>", sym); + } + fn = (std::remove_reference_t<decltype(fn)>)p; + }; + + // Look up this symbol and copy it to our local array. + tree* trees; + findsym (trees, "cp_global_trees"); + memcpy (cp_global_trees, trees, sizeof (cp_global_trees)); + + // Variable pointers. + + findsym (scope_chain_ptr, "scope_chain"); + + cpp_reader** parse_in_ptr = nullptr; + findsym (parse_in_ptr, "parse_in"); + parse_in = *parse_in_ptr; + + + // Function pointers. + + findsym (real_c_register_pragma, "_Z17c_register_pragmaPKcS0_PFvP10cpp_readerE"); + findsym (real_cpp_define, "_Z10cpp_defineP10cpp_readerPKc"); + findsym (real_strip_typedefs, "_Z14strip_typedefsP9tree_nodePbj"); + findsym (real_lookup_base, +#if GCC_VERSION >= 14000 + "_Z11lookup_baseP9tree_nodeS0_iP9base_kindil" +#else + "_Z11lookup_baseP9tree_nodeS0_iP9base_kindi" +#endif + ); + findsym (real_type_as_string, "_Z14type_as_stringP9tree_nodei"); + findsym (real_decl_as_string, "_Z14decl_as_stringP9tree_nodei"); + findsym (real_skip_artificial_parms_for, "_Z25skip_artificial_parms_forPK9tree_nodePS_"); + findsym (real_dfs_walk_all, "_Z12dfs_walk_allP9tree_nodePFS0_S0_PvES3_S1_"); + findsym (real_cp_type_quals, "_Z13cp_type_qualsPK9tree_node"); + findsym (real_look_for_overrides_here, "_Z23look_for_overrides_hereP9tree_nodeS0_"); + + return true; +} + + +} // namespace CheckerGccPlugins + diff --git a/External/CheckerGccPlugins/src/feshim.h b/External/CheckerGccPlugins/src/feshim.h new file mode 100644 index 0000000000000000000000000000000000000000..c125c3c1600c3337955e34522e0563048912db07 --- /dev/null +++ b/External/CheckerGccPlugins/src/feshim.h @@ -0,0 +1,95 @@ +// This file's extension implies that it's C, but it's really -*- C++ -*-. +/* + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration. + */ +/** + * @file CheckerGccPlugins/src/feshim.h + * @author scott snyder <snyder@bnl.gov> + * @date Apr, 2024 + * @brief Shims for accessing front-end symbols. + * + * In the cmake builds, the -fplugin switch will be given for both + * the compile and link steps. Normally, when that switch is given + * during linking, it will not have any effect. But if link-time + * optimization (LTO) is being done, then the compiler will run at link + * time and the plugin gets loaded. The problem then is that it's not + * the full compiler that runs, but only the middle/backend. If the + * plugin references symbols from the frontend, then it will fail + * to load during the link step, causing the link to fail. + * (gcc will load the plugin with RTLD_NOW.) + * + * To resolve this, we launder references to FE symbols through + * the shims defined here, which access the symbols via dlsym(). + * If the first symbol is missing then we return gracefully and + * disable the checkers. + */ + + +#ifndef CHECKERGCCPLUGINS_FESHIM_H +#define CHECKERGCCPLUGINS_FESHIM_H + + +#include "tree-core.h" + + +struct cpp_reader; + + +namespace CheckerGccPlugins +{ + + +// +// Initialize shims for accessing symbols from the front-end. +// Returns true on success, false if frontend symbols are not available. +// +bool init_shims(); + + +// The shim functions. + + +typedef void (*pragma_handler_1arg)(struct cpp_reader *); +void c_register_pragma (const char *space, const char *name, + pragma_handler_1arg handler); + +void cpp_define (const char* def); + + +tree strip_typedefs (tree t, + bool* remove_attributes = NULL, + unsigned int flags = 0); + +tree lookup_base (tree t, tree base); + +const char* type_as_string (tree t, int flags); + +const char* decl_as_string (tree t, int flags); + +tree skip_artificial_parms_for (const_tree fn, tree list); + +tree +dfs_walk_all (tree binfo, tree (*pre_fn) (tree, void *), + tree (*post_fn) (tree, void *), void *data); + + +int cp_type_quals (const_tree t); + + +tree look_for_overrides_here (tree type, tree fndecl); + + +tree get_current_namespace(); + + +} // namespace CheckerGccPlugins + + +// Define this here so that the macros in cp-tree.h that use this function +// will pick up the shim instead. +#ifndef FESHIM_CXX +#define cp_type_quals CheckerGccPlugins::cp_type_quals +#endif + + +#endif // not CHECKERGCCPLUGINS_FESHIM_H diff --git a/External/CheckerGccPlugins/src/gaudi_inheritance_plugin.cxx b/External/CheckerGccPlugins/src/gaudi_inheritance_plugin.cxx index ee0ea09cbacc032c41f2f9e569d5a19207637631..ae482f6e34f039dccfc208c22b5d0bb710a6f769 100644 --- a/External/CheckerGccPlugins/src/gaudi_inheritance_plugin.cxx +++ b/External/CheckerGccPlugins/src/gaudi_inheritance_plugin.cxx @@ -11,7 +11,7 @@ * The AthenaBaseComps classes themselves (AthAlgorithm, AthAlgTool, * AthService) are excluded from the check. * - * Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ @@ -21,6 +21,7 @@ #include "cp/cp-tree.h" #include "diagnostic.h" #include "print-tree.h" +#include "feshim.h" namespace { @@ -33,10 +34,10 @@ const char* type_name (tree t) { unsigned int save = flag_sanitize; flag_sanitize = 0; - const char* ret = type_as_string (t, - TFF_PLAIN_IDENTIFIER + - //TFF_UNQUALIFIED_NAME + - TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS); + const char* ret = CheckerGccPlugins::type_as_string (t, + TFF_PLAIN_IDENTIFIER + + //TFF_UNQUALIFIED_NAME + + TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS); flag_sanitize = save; return ret; } diff --git a/External/CheckerGccPlugins/src/naming_plugin.cxx b/External/CheckerGccPlugins/src/naming_plugin.cxx index e71c1a301ed902aadd51ce927595c5246a8f70a9..f5442a8dcae9a9a172374d71ca8800b46adc394b 100644 --- a/External/CheckerGccPlugins/src/naming_plugin.cxx +++ b/External/CheckerGccPlugins/src/naming_plugin.cxx @@ -4,7 +4,7 @@ * @date Aug, 2015 * @brief Check ATLAS naming conventions. * - * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ @@ -33,6 +33,7 @@ #include "tree-phinodes.h" #include "gimple-ssa.h" #include "ssa-iterators.h" +#include "feshim.h" #if GCC_VERSION < 12000 @@ -115,8 +116,7 @@ bool ignore_decl_p1 (tree decl) // Ignore classes deriving from SG::IAuxStore. if (TREE_CODE (type) == RECORD_TYPE && iauxstore_type) { - tree base = lookup_base (type, iauxstore_type, - ba_any, NULL, tf_none); + tree base = CheckerGccPlugins::lookup_base (type, iauxstore_type); if (base != NULL_TREE && base != error_mark_node) return true; } @@ -364,10 +364,11 @@ void naming_finishdecl_callback (void* gcc_data, void* /*user_data*/) // Gaudi plugin service v2 if (strncmp (name, "_register_", 10) == 0 && !TREE_PUBLIC (decl)) { - const char* name = type_as_string (TREE_TYPE (decl), - TFF_PLAIN_IDENTIFIER + - TFF_SCOPE + - TFF_CHASE_TYPEDEF); + const char* name = CheckerGccPlugins::type_as_string + (TREE_TYPE (decl), + TFF_PLAIN_IDENTIFIER + + TFF_SCOPE + + TFF_CHASE_TYPEDEF); if (strncmp (name, "Gaudi::PluginService::", 22) == 0) { return; } diff --git a/External/CheckerGccPlugins/src/thread_plugin.cxx b/External/CheckerGccPlugins/src/thread_plugin.cxx index 8435bb9374d239ee9be8985f961f1aaf5f4c60ab..e470fb383f733a757b459c877b618a6a27a89d17 100644 --- a/External/CheckerGccPlugins/src/thread_plugin.cxx +++ b/External/CheckerGccPlugins/src/thread_plugin.cxx @@ -4,7 +4,7 @@ * @date Sep, 2015 * @brief Check for possible thread-safety violations. * - * Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration */ // FIXME: can i unify pointer_is_const_arg / expr_from_arg_p / expr_from_static_p / value_from_struct? @@ -41,6 +41,7 @@ #include <unordered_map> #include "stringpool.h" #include "attribs.h" +#include "feshim.h" using namespace CheckerGccPlugins; @@ -151,11 +152,7 @@ const pass_data thread_pass_data = { GIMPLE_PASS, /* type */ "thread", /* name */ -#if GCC_VERSION < 9000 - 0, /* optinfo_flags */ -#else OPTGROUP_NONE, /* optinfo_flags */ -#endif TV_NONE, /* tv_id */ 0, /* properties_required */ 0, /* properties_provided */ @@ -194,10 +191,10 @@ const char* type_name (tree t) { unsigned int save = flag_sanitize; flag_sanitize = 0; - const char* ret = type_as_string (t, - TFF_PLAIN_IDENTIFIER + - //TFF_UNQUALIFIED_NAME + - TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS); + const char* ret = CheckerGccPlugins::type_as_string (t, + TFF_PLAIN_IDENTIFIER + + //TFF_UNQUALIFIED_NAME + + TFF_NO_OMIT_DEFAULT_TEMPLATE_ARGUMENTS); flag_sanitize = save; return ret; } @@ -323,10 +320,10 @@ bool is_in_std (tree decl_or_type) // Is TYPE a mutex type? bool is_mutex (tree type) { - const char* name = type_as_string (type, - TFF_PLAIN_IDENTIFIER + - TFF_SCOPE + - TFF_CHASE_TYPEDEF); + const char* name = CheckerGccPlugins::type_as_string (type, + TFF_PLAIN_IDENTIFIER + + TFF_SCOPE + + TFF_CHASE_TYPEDEF); if (strcmp (name, "std::mutex") == 0) return true; if (strcmp (name, "std::shared_mutex") == 0) return true; if (strcmp (name, "std::shared_timed_mutex") == 0) return true; @@ -353,10 +350,10 @@ bool is_mutex_maybearr (tree type) bool is_atomic (tree type) { if (TREE_CODE (type) != RECORD_TYPE) return false; - const char* name = type_as_string (type, - TFF_PLAIN_IDENTIFIER + - TFF_SCOPE + - TFF_CHASE_TYPEDEF); + const char* name = CheckerGccPlugins::type_as_string (type, + TFF_PLAIN_IDENTIFIER + + TFF_SCOPE + + TFF_CHASE_TYPEDEF); if (strncmp (name, "const ", 6) == 0) name += 6; @@ -404,7 +401,9 @@ bool is_atomic_maybearr (tree type) // True if the first argument of FNDECL is a TBuffer pointer or reference.. bool has_tbuffer_arg (tree fndecl) { - tree args = FUNCTION_FIRST_USER_PARMTYPE (fndecl); + //tree args = FUNCTION_FIRST_USER_PARMTYPE (fndecl); + tree args = CheckerGccPlugins::skip_artificial_parms_for + (fndecl, TYPE_ARG_TYPES (TREE_TYPE (fndecl))); if (!args) return false; tree arg = TREE_VALUE (args); if (!arg) return false; @@ -423,10 +422,10 @@ bool has_tbuffer_arg (tree fndecl) // Is TYPE a thread-local type? bool is_thread_local (tree type) { - const char* name = type_as_string (type, - TFF_PLAIN_IDENTIFIER + - TFF_SCOPE + - TFF_CHASE_TYPEDEF); + const char* name = CheckerGccPlugins::type_as_string (type, + TFF_PLAIN_IDENTIFIER + + TFF_SCOPE + + TFF_CHASE_TYPEDEF); if (strncmp (name, "boost::thread_specific_ptr<", 27) == 0) return true; return false; } @@ -440,6 +439,10 @@ bool static_p (tree expr) return false; } +#if GCC_VERSION >= 14000 + if (TREE_CODE (expr) == CONSTRUCTOR) return false; +#endif + if (DECL_P (expr)) { if (TREE_CODE (expr) == FUNCTION_DECL) return false; if (DECL_THREAD_LOCAL_P (expr)) return false; @@ -464,7 +467,12 @@ bool static_p (tree expr) bool const_p (tree expr) { +#if GCC_VERSION < 14000 + // Maybe this was never needed? + // But with gcc14, this can be set for non-const static variables + // with no state. if (TREE_CONSTANT (expr)) return true; +#endif if (TREE_READONLY (expr)) return true; tree typ = TREE_TYPE (expr); if (typ && TREE_CODE (typ) == REFERENCE_TYPE) { @@ -518,7 +526,7 @@ bool is_service (tree typ) std::string bname; tree binfo = TYPE_BINFO (typ); if (!binfo) return false; - if (dfs_walk_all (binfo, service_test, nullptr, &bname) != nullptr) { + if (CheckerGccPlugins::dfs_walk_all (binfo, service_test, nullptr, &bname) != nullptr) { if (bname == "IInterface") { std::string typ_name = type_name (typ); return endswith (typ_name.c_str(), "Svc"); @@ -1534,7 +1542,11 @@ void check_nonconst_call_from_const_member (tree fndecl, function* fun) { if (!DECL_CONST_MEMFUNC_P (fun->decl)) return; +#if GCC_VERSION >= 14000 + if (!DECL_OBJECT_MEMBER_FUNCTION_P (fndecl) || DECL_CONST_MEMFUNC_P (fndecl)) return; +#else if (!DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) || DECL_CONST_MEMFUNC_P (fndecl)) return; +#endif if (gimple_call_num_args (stmt) < 1) return; tree arg0 = gimple_call_arg (stmt, 0); if (TREE_CODE (arg0) != SSA_NAME) return; @@ -1727,7 +1739,11 @@ void check_nonconst_pointer_member_passing (tree fndecl, // If we're calling a non-static member function, don't check for the // first (this) argument. That will be checked separately. if (!fndecl) return; +#if GCC_VERSION >= 14000 + if (DECL_OBJECT_MEMBER_FUNCTION_P (fndecl) && i == 0) return; +#else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fndecl) && i == 0) return; +#endif // Don't warn about thread-safe libc functions. if (is_cstdlib (fndecl).second) return; @@ -2009,7 +2025,7 @@ void find_overridden_functions_r (tree type, tree fndecl, std::vector<tree>& basedecls) { - tree fn = look_for_overrides_here (type, fndecl); + tree fn = CheckerGccPlugins::look_for_overrides_here (type, fndecl); if (fn) { basedecls.push_back (fn); return; @@ -2121,22 +2137,95 @@ void thread_finishdecl_callback (void* gcc_data, void* /*user_data*/) } +//****************************************************************************** +// Dummy do-nothing pass. Used to replace free_lang_data in LTO builds. +// See below. +// + +const pass_data dummy_pass_data = +{ + SIMPLE_IPA_PASS, /* type */ + "*dummy", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ +}; + + +class dummy_pass : public simple_ipa_opt_pass +{ +public: + dummy_pass (gcc::context* ctxt) + : simple_ipa_opt_pass (dummy_pass_data, ctxt) + { + } + + virtual unsigned int execute (function* ) override + { return 0; } + + virtual opt_pass* clone() override { return new dummy_pass(*this); } +}; + + } // anonymous namespace void init_thread_checker (plugin_name_args* plugin_info) { - struct register_pass_info pass_info = { + struct register_pass_info thread_pass_info = { new thread_pass(g), "ssa", 0, PASS_POS_INSERT_AFTER }; - + register_callback (plugin_info->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL, - &pass_info); + &thread_pass_info); + + // The free_lang_data pass runs just after gimplification + // (and before the conversion to SSA). Normally, it doesn't do much, + // but if LTO is enabled, then it will free the C++-specific parts + // from the types and declarations. However, the thread checker + // relies on this information. Further, dataflow analysis requires that + // the SSA conversion has taken place, so we can't just shift it + // to before free_lang_data. But it doesn't really matter that much + // exactly where free_lang_data runs, so we instead move it to slightly + // later, after the checker runs. + // + // The plugin API doesn't seem to provide a way to reorder existing passes, + // so we do this by replacing free_lang_data with a dummy and then adding + // a new instance of it further on. + if (flag_lto) { + struct register_pass_info dummy_pass_info = { + new dummy_pass(g), + "*free_lang_data", + 0, + PASS_POS_REPLACE + }; + + struct register_pass_info freelang_pass_info = { + make_pass_ipa_free_lang_data(g), + "build_ssa_passes", + 1, + PASS_POS_INSERT_AFTER + }; + + register_callback (plugin_info->base_name, + PLUGIN_PASS_MANAGER_SETUP, + NULL, + &dummy_pass_info); + + register_callback (plugin_info->base_name, + PLUGIN_PASS_MANAGER_SETUP, + NULL, + &freelang_pass_info); + } register_callback (plugin_info->base_name, PLUGIN_FINISH_TYPE, diff --git a/External/CheckerGccPlugins/src/usingns_plugin.cxx b/External/CheckerGccPlugins/src/usingns_plugin.cxx index 09f8514f09ba2ff086311a7a25355b2214b64bba..3d03bdef659d3af5fa3df77c542e12790c09041c 100644 --- a/External/CheckerGccPlugins/src/usingns_plugin.cxx +++ b/External/CheckerGccPlugins/src/usingns_plugin.cxx @@ -1,5 +1,5 @@ /** - * Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration + * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration * * @file CheckerGccPlugins/src/usingns_plugin.cxx * @author scott snyder <snyder@bnl.gov> @@ -45,6 +45,7 @@ #include "tree-phinodes.h" #include "gimple-ssa.h" #include "ssa-iterators.h" +#include "feshim.h" #if GCC_VERSION < 12000 @@ -84,7 +85,7 @@ std::vector<location_t> global_using_decls; void handle_using_decl (tree /*decl*/) { // Only warn about declarations in the global namespace. - if (current_namespace == global_namespace) + if (CheckerGccPlugins::get_current_namespace() == global_namespace) { // Give a warning now if this decl was from a header file. // nb. DECL_SOURCE_LOCATION(decl) is not reliable. @@ -140,7 +141,7 @@ std::vector<location_t> global_using_stmts; void handle_using_stmt (tree stmt) { // Only warn if we're in the global namespace. - if (current_namespace != global_namespace) return; + if (CheckerGccPlugins::get_current_namespace() != global_namespace) return; if (current_function_decl) return; // Give a warning now if we're in a header file. diff --git a/External/CheckerGccPlugins/test/checker_ltolink_test.sh.in b/External/CheckerGccPlugins/test/checker_ltolink_test.sh.in new file mode 100755 index 0000000000000000000000000000000000000000..fcc6d7b659ef10179c384c03ba79d15fe0dfdbc6 --- /dev/null +++ b/External/CheckerGccPlugins/test/checker_ltolink_test.sh.in @@ -0,0 +1,8 @@ +#!/bin/sh +# +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration +# + +@CMAKE_CXX_COMPILER@ -c -o @testName@_test.o $EXTRA_FLAGS --std=c++20 @_checkerTestFlags@ -fplugin=@CMAKE_LIBRARY_OUTPUT_DIRECTORY@/libchecker_gccplugins.so -fplugin-arg-libchecker_gccplugins-checkers=all @CMAKE_CURRENT_SOURCE_DIR@/test/@testName@_test.cxx +@CMAKE_CXX_COMPILER@ $EXTRA_FLAGS --std=c++20 @_checkerTestFlags@ -fplugin=@CMAKE_LIBRARY_OUTPUT_DIRECTORY@/libchecker_gccplugins.so -fplugin-arg-libchecker_gccplugins-checkers=all @testName@_test.o -o @testName@_test.exe + diff --git a/External/CheckerGccPlugins/test/checker_test.sh.in b/External/CheckerGccPlugins/test/checker_test.sh.in index 55b6d5f4ea62c559ccb7ef5a38ab06f28ffa2305..db0cd8954cb08f584b435ab3a433ec45cef88a6a 100755 --- a/External/CheckerGccPlugins/test/checker_test.sh.in +++ b/External/CheckerGccPlugins/test/checker_test.sh.in @@ -1,6 +1,6 @@ #!/bin/sh # -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration # # Diagnostic format changed in gcc9, but can be changed back to the old format @@ -12,5 +12,5 @@ if [ $MAJOR_VERSION -ge 9 ]; then EXTRA_FLAGS="-fno-diagnostics-show-line-numbers" fi -@CMAKE_CXX_COMPILER@ -c -o /dev/null $EXTRA_FLAGS -fdiagnostics-generate-patch --std=c++17 @_checkerTestFlags@ -fplugin=@CMAKE_LIBRARY_OUTPUT_DIRECTORY@/libchecker_gccplugins.so -fplugin-arg-libchecker_gccplugins-checkers=all @CMAKE_CURRENT_SOURCE_DIR@/test/@testName@_test.cxx +@CMAKE_CXX_COMPILER@ -c -o /dev/null $EXTRA_FLAGS -fdiagnostics-generate-patch --std=c++20 @_checkerTestFlags@ -fplugin=@CMAKE_LIBRARY_OUTPUT_DIRECTORY@/libchecker_gccplugins.so -fplugin-arg-libchecker_gccplugins-checkers=all @CMAKE_CURRENT_SOURCE_DIR@/test/@testName@_test.cxx diff --git a/External/CheckerGccPlugins/test/ltolink_test.cxx b/External/CheckerGccPlugins/test/ltolink_test.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f8b643afbf2c84dc03b777743d3e53a22045cf49 --- /dev/null +++ b/External/CheckerGccPlugins/test/ltolink_test.cxx @@ -0,0 +1,4 @@ +int main() +{ + return 0; +} diff --git a/External/CheckerGccPlugins/test/thread14_test.cxx b/External/CheckerGccPlugins/test/thread14_test.cxx index c141359e3fedba6c4217527a983dcf43c753787b..2c29fccb17cd0f76b8f7e7384a49d97f96c4bbf1 100644 --- a/External/CheckerGccPlugins/test/thread14_test.cxx +++ b/External/CheckerGccPlugins/test/thread14_test.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration +// Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration // // thread14_test: testing check_direct_static_use/check_assign_address_of_static // with a const static object @@ -59,4 +59,10 @@ const int* f12() return &s2.x; } +void f20() +{ + [[maybe_unused]] int a[256] = {0}; +} + +