From f4ee2a02344e25331c76e4ef8a4c80339aa85e12 Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Sun, 7 Oct 2018 21:52:57 -0700 Subject: [PATCH] [inferbo] Revise placement new model Summary: It enables placement_new to get three parameters, which happens when placement_new is overloaded (e.g. Boost). Reviewed By: mbouaziz Differential Revision: D10100324 fbshipit-source-id: 0ecb0a404 --- infer/src/IR/Typ.ml | 2 + infer/src/IR/Typ.mli | 2 + .../src/bufferoverrun/bufferOverrunModels.ml | 30 +++++-- .../codetoanalyze/cpp/bufferoverrun/class.cpp | 79 +++++++++++++++++++ .../cpp/bufferoverrun/issues.exp | 7 ++ 5 files changed, 113 insertions(+), 7 deletions(-) diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index fa888d197..47d7b6a38 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -480,6 +480,8 @@ let is_reference typ = match typ.desc with Tptr (_, Pk_reference) -> true | _ -> let is_pointer_to_cpp_class typ = match typ.desc with Tptr (t, _) -> is_cpp_class t | _ -> false +let is_pointer_to_void typ = match typ.desc with Tptr ({desc= Tvoid}, _) -> true | _ -> false + let has_block_prefix s = match Str.split_delim (Str.regexp_string Config.anonymous_block_prefix) s with | _ :: _ :: _ -> diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index c2e608655..997632c54 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -258,6 +258,8 @@ val is_cpp_class : t -> bool val is_pointer_to_cpp_class : t -> bool +val is_pointer_to_void : t -> bool + val is_pointer : t -> bool val is_reference : t -> bool diff --git a/infer/src/bufferoverrun/bufferOverrunModels.ml b/infer/src/bufferoverrun/bufferOverrunModels.ml index 3d96cfbe1..ea0e29ab6 100644 --- a/infer/src/bufferoverrun/bufferOverrunModels.ml +++ b/infer/src/bufferoverrun/bufferOverrunModels.ml @@ -168,12 +168,28 @@ let realloc src_exp size_exp = {exec; check} -let placement_new allocated_mem_exp = - let exec _ ~ret:(id, _) mem = - let v = Sem.eval allocated_mem_exp mem in - Dom.Mem.add_stack (Loc.of_id id) v mem - in - {exec; check= no_check} +let placement_new size_exp (src_exp1, t1) src_arg2_opt = + match (t1.Typ.desc, src_arg2_opt) with + | Tint _, None | Tint _, Some (_, {Typ.desc= Tint _}) -> + malloc (Exp.BinOp (Binop.PlusA, size_exp, src_exp1)) + | Tstruct (CppClass (name, _)), None + when [%compare.equal: string list] (QualifiedCppName.to_list name) ["std"; "nothrow_t"] -> + malloc size_exp + | _, _ -> + let exec _ ~ret:(id, _) mem = + let src_exp = + if Typ.is_pointer_to_void t1 then src_exp1 + else + match src_arg2_opt with + | Some (src_exp2, t2) when Typ.is_pointer_to_void t2 -> + src_exp2 + | _ -> + L.(die InternalError) "Unexpected types of arguments for __placement_new" + in + let v = Sem.eval src_exp mem in + Dom.Mem.add_stack (Loc.of_id id) v mem + in + {exec; check= no_check} let inferbo_min e1 e2 = @@ -484,7 +500,7 @@ module Call = struct $+...$--> Collection.new_list ; -"__new" <>$ capt_exp $+...$--> malloc ; -"__new_array" <>$ capt_exp $+...$--> malloc - ; -"__placement_new" <>$ any_arg $+ capt_exp $!--> placement_new + ; -"__placement_new" <>$ capt_exp $+ capt_arg $+? capt_arg $!--> placement_new ; -"realloc" <>$ capt_exp $+ capt_exp $+...$--> realloc ; -"__get_array_length" <>$ capt_exp $!--> get_array_length ; -"__set_array_length" <>$ capt_arg $+ capt_exp $!--> set_array_length diff --git a/infer/tests/codetoanalyze/cpp/bufferoverrun/class.cpp b/infer/tests/codetoanalyze/cpp/bufferoverrun/class.cpp index 9c1e23192..8d4f743b6 100644 --- a/infer/tests/codetoanalyze/cpp/bufferoverrun/class.cpp +++ b/infer/tests/codetoanalyze/cpp/bufferoverrun/class.cpp @@ -65,6 +65,16 @@ void array_member_malloc2_Bad() { #include +void new_nothrow_Good() { + my_class2* x = new (std::nothrow) my_class2(); + x->a[0] = 0; +} + +void new_nothrow_Bad() { + my_class2* x = new (std::nothrow) my_class2(); + x->a[10] = 0; +} + void placement_new_Good() { char* mem = (char*)malloc(sizeof(my_class2)); my_class2* x = new (mem) my_class2(); @@ -77,6 +87,50 @@ void placement_new_Bad() { x->a[10] = 0; } +enum class DummyClass {}; +inline void* operator new(std::size_t, DummyClass, void* p) { return p; } +inline void* operator new(std::size_t, void* p, DummyClass) { return p; } + +void placement_new_overload1_Good() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (DummyClass{}, mem) my_class2(); + x->a[0] = 0; +} + +void placement_new_overload1_Bad() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (DummyClass{}, mem) my_class2(); + x->a[10] = 0; +} + +void placement_new_overload2_Good() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (mem, DummyClass{}) my_class2(); + x->a[0] = 0; +} + +void placement_new_overload2_Bad() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (mem, DummyClass{}) my_class2(); + x->a[10] = 0; +} + +struct DummyStruct {}; +inline void* operator new(std::size_t, DummyStruct, void* p) { return p; } +inline void* operator new(std::size_t, void* p, DummyStruct) { return p; } + +void placement_new_overload3_Good_FP() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (DummyStruct{}, mem) my_class2(); + x->a[0] = 0; +} + +void placement_new_overload4_Good_FP() { + char* mem = (char*)malloc(sizeof(my_class2)); + my_class2* x = new (mem, DummyStruct{}) my_class2(); + x->a[0] = 0; +} + class my_class4 { public: int a[3]; @@ -108,6 +162,31 @@ void flexible_array3_Bad_FN() { x->b[5] = 0; } +void* operator new(std::size_t s1, std::size_t s2) { return malloc(s1 + s2); } +void* operator new(std::size_t s1, std::size_t s2, bool) { + return malloc(s1 + s2); +} + +void flexible_array_new_overload1_Good() { + my_class4* x = new (5 * sizeof(int)) my_class4(); + x->b[5] = 0; +} + +void flexible_array_new_overload1_Bad() { + my_class4* x = new (5 * sizeof(int)) my_class4(); + x->b[10] = 0; +} + +void flexible_array_new_overload2_Good() { + my_class4* x = new (5 * sizeof(int), true) my_class4(); + x->b[5] = 0; +} + +void flexible_array_new_overload2_Bad() { + my_class4* x = new (5 * sizeof(int), true) my_class4(); + x->b[10] = 0; +} + class my_class5 { public: int d[3]; diff --git a/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp b/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp index dee60773e..336401847 100644 --- a/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp +++ b/infer/tests/codetoanalyze/cpp/bufferoverrun/issues.exp @@ -4,10 +4,17 @@ codetoanalyze/cpp/bufferoverrun/class.cpp, array_member_malloc_Bad, 2, BUFFER_OV codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array1_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 5 Size: 5] codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array4_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 5 Size: 5] codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array5_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,Call,Return,Call,Parameter: nth,ArrayAccess: Offset: 5 Size: 3 by call to `Tree_set_child` ] +codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array_new_overload1_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 6] +codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array_new_overload2_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 6] codetoanalyze/cpp/bufferoverrun/class.cpp, flexible_array_param_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,ArrayAccess: Offset: 3 Size: 3 by call to `flexible_array_param_access` ] codetoanalyze/cpp/bufferoverrun/class.cpp, my_class_access2_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,Assignment,Call,Parameter: n,Assignment,Return,ArrayAccess: Offset: 10 Size: 10] codetoanalyze/cpp/bufferoverrun/class.cpp, my_class_access_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Call,Call,Parameter: n,Assignment,ArrayAccess: Offset: 10 Size: 10] +codetoanalyze/cpp/bufferoverrun/class.cpp, new_nothrow_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 5] codetoanalyze/cpp/bufferoverrun/class.cpp, placement_new_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 5] +codetoanalyze/cpp/bufferoverrun/class.cpp, placement_new_overload1_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 5] +codetoanalyze/cpp/bufferoverrun/class.cpp, placement_new_overload2_Bad, 3, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Offset: 10 Size: 5] +codetoanalyze/cpp/bufferoverrun/class.cpp, placement_new_overload3_Good_FP, 3, BUFFER_OVERRUN_U5, no_bucket, ERROR, [Unknown value from: my_class2_my_class2,ArrayAccess: Offset: [-oo, +oo] Size: [0, +oo]] +codetoanalyze/cpp/bufferoverrun/class.cpp, placement_new_overload4_Good_FP, 3, BUFFER_OVERRUN_U5, no_bucket, ERROR, [Unknown value from: my_class2_my_class2,ArrayAccess: Offset: [-oo, +oo] Size: [0, +oo]] codetoanalyze/cpp/bufferoverrun/class.cpp, return_class_Bad, 2, BUFFER_OVERRUN_L1, no_bucket, ERROR, [Return,ArrayAccess: Offset: 5 Size: 5] codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 5, BUFFER_OVERRUN_U5, no_bucket, ERROR, [Unknown value from: lib,Assignment,ArrayAccess: Offset: [-oo, +oo] Size: [0, +oo]] codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 10, BUFFER_OVERRUN_L1, no_bucket, ERROR, [ArrayDeclaration,ArrayAccess: Offset: 30 Size: 10]