[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
master
Sungkeun Cho 6 years ago committed by Facebook Github Bot
parent aa6f5b2ed5
commit f4ee2a0234

@ -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_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 = let has_block_prefix s =
match Str.split_delim (Str.regexp_string Config.anonymous_block_prefix) s with match Str.split_delim (Str.regexp_string Config.anonymous_block_prefix) s with
| _ :: _ :: _ -> | _ :: _ :: _ ->

@ -258,6 +258,8 @@ val is_cpp_class : t -> bool
val is_pointer_to_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_pointer : t -> bool
val is_reference : t -> bool val is_reference : t -> bool

@ -168,12 +168,28 @@ let realloc src_exp size_exp =
{exec; check} {exec; check}
let placement_new allocated_mem_exp = let placement_new size_exp (src_exp1, t1) src_arg2_opt =
let exec _ ~ret:(id, _) mem = match (t1.Typ.desc, src_arg2_opt) with
let v = Sem.eval allocated_mem_exp mem in | Tint _, None | Tint _, Some (_, {Typ.desc= Tint _}) ->
Dom.Mem.add_stack (Loc.of_id id) v mem malloc (Exp.BinOp (Binop.PlusA, size_exp, src_exp1))
in | Tstruct (CppClass (name, _)), None
{exec; check= no_check} 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 = let inferbo_min e1 e2 =
@ -484,7 +500,7 @@ module Call = struct
$+...$--> Collection.new_list $+...$--> Collection.new_list
; -"__new" <>$ capt_exp $+...$--> malloc ; -"__new" <>$ capt_exp $+...$--> malloc
; -"__new_array" <>$ 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 ; -"realloc" <>$ capt_exp $+ capt_exp $+...$--> realloc
; -"__get_array_length" <>$ capt_exp $!--> get_array_length ; -"__get_array_length" <>$ capt_exp $!--> get_array_length
; -"__set_array_length" <>$ capt_arg $+ capt_exp $!--> set_array_length ; -"__set_array_length" <>$ capt_arg $+ capt_exp $!--> set_array_length

@ -65,6 +65,16 @@ void array_member_malloc2_Bad() {
#include <new> #include <new>
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() { void placement_new_Good() {
char* mem = (char*)malloc(sizeof(my_class2)); char* mem = (char*)malloc(sizeof(my_class2));
my_class2* x = new (mem) my_class2(); my_class2* x = new (mem) my_class2();
@ -77,6 +87,50 @@ void placement_new_Bad() {
x->a[10] = 0; 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 { class my_class4 {
public: public:
int a[3]; int a[3];
@ -108,6 +162,31 @@ void flexible_array3_Bad_FN() {
x->b[5] = 0; 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 { class my_class5 {
public: public:
int d[3]; int d[3];

@ -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_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_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_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, 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_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, 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_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/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, 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] codetoanalyze/cpp/bufferoverrun/external.cpp, extern_bad, 10, BUFFER_OVERRUN_L1, no_bucket, ERROR, [ArrayDeclaration,ArrayAccess: Offset: 30 Size: 10]

Loading…
Cancel
Save