[infer] NULLPTR_DEREFERENCE false positive caused by thread_local variable

Summary:
Keyword `thread_local` in cpp allows us to create a variable with thread storage duration, meaning that the object's lifetime begins when the thread begins and ends when the thread ends.

We get `NULLPTR_DEREFERENCE` false positive for `thread_local` variable since we reallocate it in the `VariableLifetimeBegins` metadata instruction and we do not see further updates to the variable. To solve the issue we special case `VariableLifetimeBegins`  instruction for global variables.

Reviewed By: jvillard

Differential Revision: D22284135

fbshipit-source-id: 13c14ef90
master
Daiva Naudziuniene 4 years ago committed by Facebook GitHub Bot
parent 70233b55f1
commit 0ab3689f1f

@ -281,9 +281,9 @@ module PulseTransferFunctions = struct
if List.is_empty ret_vars then vars else List.rev_append vars ret_vars
in
remove_vars vars_to_remove astates
| Metadata (VariableLifetimeBegins (pvar, _, location)) ->
| Metadata (VariableLifetimeBegins (pvar, _, location)) when not (Pvar.is_global pvar) ->
[PulseOperations.realloc_pvar pvar location astate |> Domain.continue]
| Metadata (Abstract _ | Nullify _ | Skip) ->
| Metadata (Abstract _ | VariableLifetimeBegins _ | Nullify _ | Skip) ->
[Domain.ContinueProgram astate] )

@ -122,3 +122,35 @@ X* getX(bool b) {
}
void call_modeled_abort_ok() { getX(false)->foo(); }
struct S {
int field;
};
void set_S();
struct T {
static S*& get() {
auto& s = T::getRaw();
if (T::getRaw() == nullptr) {
set_S();
}
return s;
}
static S*& getRaw() {
thread_local S* s = nullptr;
return s;
}
};
void set_S() {
auto& s = T::getRaw();
if (s != nullptr) {
return;
}
s = (S*)calloc(1, sizeof(S));
}
int thread_local_was_set_ok() { return T::get()->field; }

Loading…
Cancel
Save