diff --git a/facebook-clang-plugins b/facebook-clang-plugins index 248d630ea..189047104 160000 --- a/facebook-clang-plugins +++ b/facebook-clang-plugins @@ -1 +1 @@ -Subproject commit 248d630ea8a64a01ca56ccb87f97acd707610660 +Subproject commit 18904710494629ff27a5350d715f3a2a228970b6 diff --git a/infer/src/IR/Pvar.re b/infer/src/IR/Pvar.re index 473f09b9e..2c500b7cc 100644 --- a/infer/src/IR/Pvar.re +++ b/infer/src/IR/Pvar.re @@ -26,7 +26,7 @@ type pvar_kind = | Abduced_retvar Procname.t Location.t /** synthetic variable to represent return value */ | Abduced_ref_param Procname.t t Location.t /** synthetic variable to represent param passed by reference */ - | Global_var (DB.source_file, bool) /** global variable: translation unit + is it compile constant? */ + | Global_var (DB.source_file, bool, bool) /** global variable: translation unit + is it compile constant? + is it POD? */ | Seed_var /** variable used to store the initial value of formal parameters */ /** Names for program variables. */ and t = {pv_name: Mangled.t, pv_kind: pvar_kind}; @@ -62,12 +62,17 @@ let rec pvar_kind_compare k1 k2 => } | (Abduced_ref_param _, _) => (-1) | (_, Abduced_ref_param _) => 1 - | (Global_var (f1, b1), Global_var (f2, b2)) => + | (Global_var (f1, const1, pod1), Global_var (f2, const2, pod2)) => let n = DB.source_file_compare f1 f2; if (n != 0) { n } else { - bool_compare b1 b2 + let n = bool_compare const1 const2; + if (n != 0) { + n + } else { + bool_compare pod1 pod2 + } } | (Global_var _, _) => (-1) | (_, Global_var _) => 1 @@ -111,9 +116,21 @@ let rec _pp f pv => { } else { F.fprintf f "%a$%a%a|abducedRefParam" Procname.pp n Location.pp l Mangled.pp name } - | Global_var (fname, b) => + | Global_var (fname, is_const, is_pod) => F.fprintf - f "#GB<%s%s>$%a" (DB.source_file_to_string fname) (if b {"|const"} else {""}) Mangled.pp name + f + "#GB<%s%s%s>$%a" + (DB.source_file_to_string fname) + (if is_const {"|const"} else {""}) + ( + if (not is_pod) { + "|!pod" + } else { + "" + } + ) + Mangled.pp + name | Seed_var => F.fprintf f "old_%a" Mangled.pp name } }; @@ -327,9 +344,9 @@ let mk_callee (name: Mangled.t) (proc_name: Procname.t) :t => { /** create a global variable with the given name */ -let mk_global is_constexpr::is_constexpr=false (name: Mangled.t) fname :t => { +let mk_global is_constexpr::is_constexpr=false is_pod::is_pod=true (name: Mangled.t) fname :t => { pv_name: name, - pv_kind: Global_var (fname, is_constexpr) + pv_kind: Global_var (fname, is_constexpr, is_pod) }; @@ -354,16 +371,22 @@ let mk_abduced_ref_param (proc_name: Procname.t) (pv: t) (loc: Location.t) :t => let get_source_file pvar => switch pvar.pv_kind { - | Global_var (f, _) => Some f + | Global_var (f, _, _) => Some f | _ => None }; let is_compile_constant pvar => switch pvar.pv_kind { - | Global_var (_, b) => b + | Global_var (_, b, _) => b | _ => false }; +let is_pod pvar => + switch pvar.pv_kind { + | Global_var (_, _, b) => b + | _ => true + }; + let get_initializer_pname {pv_name, pv_kind} => switch pv_kind { | Global_var _ => diff --git a/infer/src/IR/Pvar.rei b/infer/src/IR/Pvar.rei index 22cc0f399..50a25f23f 100644 --- a/infer/src/IR/Pvar.rei +++ b/infer/src/IR/Pvar.rei @@ -104,7 +104,7 @@ let mk_callee: Mangled.t => Procname.t => t; /** create a global variable with the given name */ -let mk_global: is_constexpr::bool? => Mangled.t => DB.source_file => t; +let mk_global: is_constexpr::bool? => is_pod::bool? => Mangled.t => DB.source_file => t; /** create a fresh temporary variable local to procedure [pname]. for use in the frontends only! */ @@ -139,10 +139,16 @@ let to_string: t => string; let get_source_file: t => option DB.source_file; -/** Is the variable's value a compile-time constant? Always [false] for non-globals. */ +/** Is the variable's value a compile-time constant? Always (potentially incorrectly) returns + [false] for non-globals. */ let is_compile_constant: t => bool; +/** Is the variable's type a "Plain Old Data" type (C++)? Always (potentially incorrectly) returns + [true] for non-globals. */ +let is_pod: t => bool; + + /** Get the procname of the initializer function for the given global variable */ let get_initializer_pname: t => option Procname.t; diff --git a/infer/src/checkers/Siof.ml b/infer/src/checkers/Siof.ml index 5b1095b8e..3b9fa8ff4 100644 --- a/infer/src/checkers/Siof.ml +++ b/infer/src/checkers/Siof.ml @@ -27,20 +27,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct module Domain = SiofDomain type extras = ProcData.no_extras - let is_semantically_compile_constant tenv pdesc pv = - match Pvar.get_initializer_pname pv with - | Some pname -> ( - match Summary.read_summary tenv pdesc pname with - | Some (Domain.NonBottom _) -> false - | Some Domain.Bottom | None -> true - ) - | None -> true - - let get_globals tenv astate pdesc loc e = + let get_globals astate loc e = let is_dangerous_global pv = Pvar.is_global pv - && not (Pvar.is_compile_constant pv - || is_semantically_compile_constant tenv pdesc pv) in + && not (Pvar.is_pod pv) + && not (Pvar.is_compile_constant pv) in let globals = Exp.get_vars e |> snd |> IList.filter is_dangerous_global in if globals = [] then Domain.Bottom @@ -55,9 +46,9 @@ module TransferFunctions (CFG : ProcCfg.S) = struct globals in Domain.NonBottom globals_trace - let add_params_globals astate tenv pdesc loc params = + let add_params_globals astate loc params = IList.map fst params - |> IList.map (fun e -> get_globals tenv astate pdesc loc e) + |> IList.map (fun e -> get_globals astate loc e) |> IList.fold_left Domain.join astate let at_least_bottom = @@ -67,7 +58,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct | Load (_, exp, _, loc) | Store (_, _, exp, loc) | Prune (exp, loc, _, _) -> - Domain.join astate (get_globals tenv astate pdesc loc exp) + Domain.join astate (get_globals astate loc exp) | Call (_, Const (Cfun callee_pname), params, loc, _) -> let callsite = CallSite.make callee_pname loc in let callee_globals = @@ -76,13 +67,13 @@ module TransferFunctions (CFG : ProcCfg.S) = struct Domain.NonBottom (SiofTrace.with_callsite trace callsite) | _ -> Domain.Bottom in - add_params_globals astate tenv pdesc loc params + add_params_globals astate loc params |> Domain.join callee_globals |> (* make sure it's not Bottom: we made a function call so this needs initialization *) at_least_bottom | Call (_, _, params, loc, _) -> - add_params_globals astate tenv pdesc loc params + add_params_globals astate loc params |> (* make sure it's not Bottom: we made a function call so this needs initialization *) at_least_bottom @@ -98,7 +89,19 @@ module Analyzer = module Interprocedural = Analyzer.Interprocedural (Summary) + +let is_foreign tu_opt v = + let is_orig_file f = match tu_opt with + | Some orig_file -> + let orig_path = DB.source_file_to_abs_path orig_file in + string_equal orig_path (DB.source_file_to_abs_path f) + | None -> assert false in + Option.map_default (fun f -> not (is_orig_file f)) false (Pvar.get_source_file v) + let report_siof tenv trace pdesc gname loc = + let tu_opt = + let attrs = Procdesc.get_attributes pdesc in + attrs.ProcAttributes.translation_unit in let trace_of_pname pname = match Summary.read_summary tenv pdesc pname with | Some (SiofDomain.NonBottom summary) -> summary @@ -129,32 +132,27 @@ let report_siof tenv trace pdesc gname loc = let report_one_path ((_, path) as sink_path) = let final_sink = fst (IList.hd path) in - let description = - F.asprintf - "The initializer of %s accesses global variables in another translation unit: %a" - gname - pp_sink final_sink in - let ltr = trace_of_error sink_path in - let caller_pname = Procdesc.get_proc_name pdesc in - let msg = Localise.to_string Localise.static_initialization_order_fiasco in - let exn = Exceptions.Checkers (msg, Localise.verbatim_desc description) in - Reporting.log_error caller_pname ~loc ~ltr exn in + if is_foreign tu_opt (SiofTrace.Sink.kind final_sink) then ( + let description = + F.asprintf + "The initializer of %s accesses global variables in another translation unit: %a" + gname + pp_sink final_sink in + let ltr = trace_of_error sink_path in + let caller_pname = Procdesc.get_proc_name pdesc in + let msg = Localise.to_string Localise.static_initialization_order_fiasco in + let exn = Exceptions.Checkers (msg, Localise.verbatim_desc description) in + Reporting.log_error caller_pname ~loc ~ltr exn + ); in IList.iter report_one_path (SiofTrace.get_reportable_sink_paths trace ~trace_of_pname) let siof_check tenv pdesc gname = function | Some (SiofDomain.NonBottom post) -> let attrs = Procdesc.get_attributes pdesc in - let is_orig_file f = match attrs.ProcAttributes.translation_unit with - | Some orig_file -> - let orig_path = DB.source_file_to_abs_path orig_file in - string_equal orig_path (DB.source_file_to_abs_path f) - | None -> false in - let is_foreign v = Option.map_default - (fun f -> not (is_orig_file f)) false (Pvar.get_source_file v) in let foreign_global_sinks = SiofTrace.Sinks.filter - (fun sink -> is_foreign (SiofTrace.Sink.kind sink)) + (fun sink -> is_foreign attrs.ProcAttributes.translation_unit (SiofTrace.Sink.kind sink)) (SiofTrace.sinks post) in if not (SiofTrace.Sinks.is_empty foreign_global_sinks) then report_siof tenv post pdesc gname attrs.ProcAttributes.loc; diff --git a/infer/src/clang/cFrontend_decl.ml b/infer/src/clang/cFrontend_decl.ml index 81eede40b..3d60719f5 100644 --- a/infer/src/clang/cFrontend_decl.ml +++ b/infer/src/clang/cFrontend_decl.ml @@ -221,14 +221,14 @@ struct | Some dec -> Logging.out "Methods of %s skipped\n" (Ast_utils.string_of_decl dec) | None -> ()) - | VarDecl (decl_info, named_decl_info, _, ({ vdi_is_global; vdi_init_expr } as vdi)) + | VarDecl (decl_info, named_decl_info, qt, ({ vdi_is_global; vdi_init_expr } as vdi)) when vdi_is_global && Option.is_some vdi_init_expr -> (* create a fake procedure that initializes the global variable so that the variable initializer can be analyzed by the backend (eg, the SIOF checker) *) let procname = (* create the corresponding global variable to get the right pname for its initializer *) - let global = General_utils.mk_sil_global_var trans_unit_ctx named_decl_info vdi in + let global = General_utils.mk_sil_global_var trans_unit_ctx named_decl_info vdi qt in (* safe to Option.get because it's a global *) Option.get (Pvar.get_initializer_pname global) in let ms = CMethod_signature.make_ms procname [] Ast_expressions.create_void_type diff --git a/infer/src/clang/cFrontend_utils.ml b/infer/src/clang/cFrontend_utils.ml index fba375913..7df3cdf12 100644 --- a/infer/src/clang/cFrontend_utils.ml +++ b/infer/src/clang/cFrontend_utils.ml @@ -781,20 +781,33 @@ struct name_string, mangled let mk_sil_global_var {CFrontend_config.source_file} ?(mk_name=fun _ x -> x) - named_decl_info var_decl_info = + named_decl_info var_decl_info qt = let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in let translation_unit = - match var_decl_info.Clang_ast_t.vdi_storage_class with - | Some "extern" -> + match (var_decl_info.Clang_ast_t.vdi_storage_class, + var_decl_info.Clang_ast_t.vdi_init_expr) with + | Some "extern", None -> + (* some compilers simply disregard "extern" when the global is given some initialisation + code, which is why we make sure that [vdi_init_expr] is None here... *) DB.source_file_empty | _ -> source_file in let is_constexpr = var_decl_info.Clang_ast_t.vdi_is_const_expr in - Pvar.mk_global ~is_constexpr (mk_name name_string simple_name) translation_unit + let is_pod = + Ast_utils.get_desugared_type qt.Clang_ast_t.qt_type_ptr + |> Option.map_default (function + | Clang_ast_t.RecordType(_, decl_ptr) -> Ast_utils.get_decl decl_ptr + | _ -> None) None + |> Option.map_default (function + | Clang_ast_t.CXXRecordDecl(_, _, _, _, _, _, _, {xrdi_is_pod}) + | Clang_ast_t.ClassTemplateSpecializationDecl(_, _, _, _, _, _, _, {xrdi_is_pod}, _) -> + xrdi_is_pod + | _ -> true) true in + Pvar.mk_global ~is_constexpr ~is_pod (mk_name name_string simple_name) translation_unit let mk_sil_var trans_unit_ctx named_decl_info decl_info_type_ptr_opt procname outer_procname = match decl_info_type_ptr_opt with - | Some (decl_info, _, var_decl_info, should_be_mangled) -> + | Some (decl_info, qt, var_decl_info, should_be_mangled) -> let name_string, simple_name = get_var_name_mangled named_decl_info var_decl_info in if var_decl_info.Clang_ast_t.vdi_is_global then let mk_name = @@ -802,7 +815,7 @@ struct Some (fun name_string _ -> Mangled.from_string ((Procname.to_string outer_procname) ^ "_" ^ name_string)) else None in - mk_sil_global_var trans_unit_ctx ?mk_name named_decl_info var_decl_info + mk_sil_global_var trans_unit_ctx ?mk_name named_decl_info var_decl_info qt else if not should_be_mangled then Pvar.mk simple_name procname else let start_location = fst decl_info.Clang_ast_t.di_source_range in diff --git a/infer/src/clang/cFrontend_utils.mli b/infer/src/clang/cFrontend_utils.mli index 3a6ec6ccd..4d03f4bbe 100644 --- a/infer/src/clang/cFrontend_utils.mli +++ b/infer/src/clang/cFrontend_utils.mli @@ -247,7 +247,7 @@ sig val mk_sil_global_var : CFrontend_config.translation_unit_context -> ?mk_name:(string -> Mangled.t -> Mangled.t) -> - Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> Pvar.t + Clang_ast_t.named_decl_info -> Clang_ast_t.var_decl_info -> Clang_ast_t.qual_type -> Pvar.t val mk_sil_var : CFrontend_config.translation_unit_context -> Clang_ast_t.named_decl_info -> var_info option -> Procname.t -> Procname.t -> Pvar.t diff --git a/infer/tests/codetoanalyze/cpp/checkers/Makefile b/infer/tests/codetoanalyze/cpp/checkers/Makefile index a32e71daa..f75641d2e 100644 --- a/infer/tests/codetoanalyze/cpp/checkers/Makefile +++ b/infer/tests/codetoanalyze/cpp/checkers/Makefile @@ -19,7 +19,8 @@ SOURCES = \ siof/pod_across_translation_units-1.cpp \ siof/pod_across_translation_units-2.cpp \ siof/pod_same_translation_unit.cpp \ - siof/siof_across_translation_units-1.cpp \ - siof/siof_across_translation_units-2.cpp \ + siof/siof.cpp \ + siof/siof_templated.cpp \ + siof/siof_different_tu.cpp \ include $(TESTS_DIR)/clang.make diff --git a/infer/tests/codetoanalyze/cpp/checkers/issues.exp b/infer/tests/codetoanalyze/cpp/checkers/issues.exp index 1946e7630..4fd445d40 100644 --- a/infer/tests/codetoanalyze/cpp/checkers/issues.exp +++ b/infer/tests/codetoanalyze/cpp/checkers/issues.exp @@ -1,4 +1,10 @@ -siof/const_use.cpp, __infer_globals_initializer_use_u, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of use_u,access to u] -siof/pod_across_translation_units-1.cpp, __infer_globals_initializer_x, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of x,call to baz,call to bar,call to foo,access to y] -siof/siof_across_translation_units-1.cpp, __infer_globals_initializer_another_global_object, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_global_object,access to another_global_object] -siof/siof_across_translation_units-1.cpp, __infer_globals_initializer_another_global_object, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_global_object,call to SomeOtherObject_SomeOtherObject,access to global_object] +siof/siof.cpp, __infer_globals_initializer_X::static_pod_accesses_non_pod, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of X::static_pod_accesses_non_pod,call to access_to_non_pod,access to global_object2] +siof/siof.cpp, __infer_globals_initializer_another_global_object, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_global_object,call to SomeOtherNonPODObject_SomeOtherNonPODObject,access to extern_global_object] +siof/siof.cpp, __infer_globals_initializer_another_global_object2, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_global_object2,call to access_to_non_pod,access to global_object2] +siof/siof.cpp, __infer_globals_initializer_another_global_object3, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_global_object3,call to access_to_templated_non_pod,access to global_object3] +siof/siof.cpp, __infer_globals_initializer_initWithGlobal, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of initWithGlobal,call to getGlobalNonPOD,access to global_object2] +siof/siof.cpp, __infer_globals_initializer_initWithStatic, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of initWithStatic,call to getFunctionStaticNonPOD,access to getFunctionStaticNonPOD_instance] +siof/siof.cpp, __infer_globals_initializer_pod_accesses_non_pod, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of pod_accesses_non_pod,call to access_to_non_pod,access to global_object2] +siof/siof_templated.cpp, __infer_globals_initializer_another_templated_global_object, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_templated_global_object,call to SomeOtherTemplatedNonPODObject<_Bool>_SomeOtherTemplatedNonPODObject,access to extern_global_object] +siof/siof_templated.cpp, __infer_globals_initializer_another_templated_global_object2, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_templated_global_object2,call to access_to_non_pod,access to global_object2] +siof/siof_templated.cpp, __infer_globals_initializer_another_templated_global_object3, 0, STATIC_INITIALIZATION_ORDER_FIASCO, [initialization of another_templated_global_object3,call to access_to_templated_non_pod,access to global_object3] diff --git a/infer/tests/codetoanalyze/cpp/checkers/siof/siof.cpp b/infer/tests/codetoanalyze/cpp/checkers/siof/siof.cpp new file mode 100644 index 000000000..063222abf --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/checkers/siof/siof.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "siof_types.h" + +extern SomeNonPODObject extern_global_object; +SomeNonPODObject global_object; + +extern int access_to_non_pod(); + +struct SomeOtherNonPODObject { + SomeOtherNonPODObject() { + global_object.some_method(); // OK, same translation unit + extern_global_object.some_method(); // bad, different translation unit + }; + + SomeOtherNonPODObject(int i) { + global_object.some_method(); // OK, same translation unit + }; +}; + +SomeOtherNonPODObject another_global_object; // SIOF! +SomeOtherNonPODObject another_global_object2(access_to_non_pod()); // SIOF! +SomeOtherNonPODObject another_global_object3( + access_to_templated_non_pod()); // SIOF! +SomeOtherNonPODObject another_global_object4(42); // OK + +int pod_accesses_non_pod = access_to_non_pod(); // SIOF! + +struct X { + static int static_pod_accesses_non_pod; +}; + +int X::static_pod_accesses_non_pod = access_to_non_pod(); // SIOF! + +SomeNonPODObject initWithStatic = getFunctionStaticNonPOD(); // OK +SomeNonPODObject initWithGlobal = getGlobalNonPOD(); // SIOF! diff --git a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-2.cpp b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-2.cpp deleted file mode 100644 index 459b5eab2..000000000 --- a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-2.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2016 - present Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -// This file exists only so that the SIOF checkers sees global_object -// being initialized via a method call. The SIOF checker could be -// improved to know that all non-POD types require initialization in -// C++. - -struct SomeObject { - void some_method(); -}; - -SomeObject global_object; diff --git a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_different_tu.cpp b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_different_tu.cpp new file mode 100644 index 000000000..5b9a3383b --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_different_tu.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "siof_types.h" + +SomeNonPODObject global_object2; + +int access_to_non_pod() { + global_object2.some_method(); + return 5; +} + +SomeTemplatedNonPODObject global_object3; + +int access_to_templated_non_pod() { return global_object3.some_method(); } + +SomeNonPODObject& getFunctionStaticNonPOD() { + static SomeNonPODObject instance; + return instance; +} + +SomeNonPODObject& getGlobalNonPOD() { return global_object2; } diff --git a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_templated.cpp b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_templated.cpp new file mode 100644 index 000000000..264b5c882 --- /dev/null +++ b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_templated.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 - present Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +#include "siof_types.h" + +extern SomeTemplatedNonPODObject extern_global_object; + +SomeTemplatedNonPODObject global_object; + +template +struct SomeOtherTemplatedNonPODObject { + SomeOtherTemplatedNonPODObject() { + global_object.some_method(); // OK, same translation unit + extern_global_object.some_method(); // bad, different translation unit + }; + + SomeOtherTemplatedNonPODObject(int i) { + global_object.some_method(); // OK, same translation unit + }; +}; + +SomeOtherTemplatedNonPODObject another_templated_global_object; // SIOF! +SomeOtherTemplatedNonPODObject another_templated_global_object2( + access_to_non_pod()); // SIOF! +SomeOtherTemplatedNonPODObject another_templated_global_object3( + access_to_templated_non_pod()); // SIOF! +SomeOtherTemplatedNonPODObject another_templated_global_object4(42); // OK diff --git a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-1.cpp b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_types.h similarity index 53% rename from infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-1.cpp rename to infer/tests/codetoanalyze/cpp/checkers/siof/siof_types.h index ec08d2f3f..f6a78e65b 100644 --- a/infer/tests/codetoanalyze/cpp/checkers/siof/siof_across_translation_units-1.cpp +++ b/infer/tests/codetoanalyze/cpp/checkers/siof/siof_types.h @@ -7,15 +7,16 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -struct SomeObject { - void some_method(); +struct SomeNonPODObject { + virtual void some_method(); }; -extern SomeObject global_object; - -struct SomeOtherObject { - SomeOtherObject() { global_object.some_method(); }; +template +struct SomeTemplatedNonPODObject { + virtual T some_method(); }; -// BAD: report SIOF here -SomeOtherObject another_global_object; +int access_to_templated_non_pod(); +int access_to_non_pod(); +SomeNonPODObject& getFunctionStaticNonPOD(); +SomeNonPODObject& getGlobalNonPOD(); diff --git a/infer/tests/codetoanalyze/cpp/frontend/globals/global_const1.cpp.dot b/infer/tests/codetoanalyze/cpp/frontend/globals/global_const1.cpp.dot index 4eadb43b5..c172ea135 100644 --- a/infer/tests/codetoanalyze/cpp/frontend/globals/global_const1.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/frontend/globals/global_const1.cpp.dot @@ -1,6 +1,6 @@ /* @generated */ digraph iCFG { -"__infer_globals_initializer_global.bdc08c089842ce08b974b22a75daf78e_3" [label="3: DeclStmt \n _fun_X_X(&#GB$global:class X *) [line 13]\n " shape="box"] +"__infer_globals_initializer_global.bdc08c089842ce08b974b22a75daf78e_3" [label="3: DeclStmt \n _fun_X_X(&#GB$global:class X *) [line 13]\n " shape="box"] "__infer_globals_initializer_global.bdc08c089842ce08b974b22a75daf78e_3" -> "__infer_globals_initializer_global.bdc08c089842ce08b974b22a75daf78e_2" ; @@ -18,7 +18,7 @@ digraph iCFG { "X_X{_ZN1XC1ERKS_}.abc525d74d1815a6e1a874d1ed502de3_1" -> "X_X{_ZN1XC1ERKS_}.abc525d74d1815a6e1a874d1ed502de3_2" ; -"test{d41d8cd98f00b204e9800998ecf8427e_Z4testv}.8c08101fe48ee96867ff8578442d10bc_3" [label="3: Return Stmt \n n$0=*&__return_param:class X * [line 15]\n _fun_X_X(&#GB$global:class X *) [line 13]\n _fun_X_X(n$0:class X *,&#GB$global:class X &) [line 15]\n " shape="box"] +"test{d41d8cd98f00b204e9800998ecf8427e_Z4testv}.8c08101fe48ee96867ff8578442d10bc_3" [label="3: Return Stmt \n n$0=*&__return_param:class X * [line 15]\n _fun_X_X(&#GB$global:class X *) [line 13]\n _fun_X_X(n$0:class X *,&#GB$global:class X &) [line 15]\n " shape="box"] "test{d41d8cd98f00b204e9800998ecf8427e_Z4testv}.8c08101fe48ee96867ff8578442d10bc_3" -> "test{d41d8cd98f00b204e9800998ecf8427e_Z4testv}.8c08101fe48ee96867ff8578442d10bc_2" ; diff --git a/infer/tests/codetoanalyze/cpp/shared/namespace/namespace.cpp.dot b/infer/tests/codetoanalyze/cpp/shared/namespace/namespace.cpp.dot index 9b0a8dd13..1216c9dab 100644 --- a/infer/tests/codetoanalyze/cpp/shared/namespace/namespace.cpp.dot +++ b/infer/tests/codetoanalyze/cpp/shared/namespace/namespace.cpp.dot @@ -18,7 +18,7 @@ digraph iCFG { "foo::Rectangle_Rectangle{_ZN3foo9RectangleC1Ev}.994e34698d49402781f481c8d7fa0e03_1" -> "foo::Rectangle_Rectangle{_ZN3foo9RectangleC1Ev}.994e34698d49402781f481c8d7fa0e03_2" ; -"__infer_globals_initializer_bar::rect.e5e9061ca63212fdc2fd329df6c073de_3" [label="3: DeclStmt \n _fun_bar::Rectangle_Rectangle(&#GB$bar::rect:class bar::Rectangle *) [line 38]\n " shape="box"] +"__infer_globals_initializer_bar::rect.e5e9061ca63212fdc2fd329df6c073de_3" [label="3: DeclStmt \n _fun_bar::Rectangle_Rectangle(&#GB$bar::rect:class bar::Rectangle *) [line 38]\n " shape="box"] "__infer_globals_initializer_bar::rect.e5e9061ca63212fdc2fd329df6c073de_3" -> "__infer_globals_initializer_bar::rect.e5e9061ca63212fdc2fd329df6c073de_2" ;