Teach the frontend to recognize STL throw wrappers

Summary:
:
There are throw wrapper functions like  `std::__throw_bad_alloc()`  defined in both libstdc++ (https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/functexcept.h) and libc++ (e.g. 907c1196a7/include/new (L145)). Folly actually exports some of them as well (diffusion/FBS/browse/master/fbcode/folly/portability/BitsFunctexcept.h). The function body of those wrappers merely throws the corresponding exception. My understanding is that the primary purpose of the wrappers is to throw the exception if everything goes well and to fall back to something reasonable when exception is disabled (e.g. when `-fno-exceptions` is passed to the compiler).
The problem is that infer doesn't really understand what those functions do, and I've seen some false positives get reported as a result of it. So to remove those FPs we need to either model them or handle them specially. Modeling those wrappers by either whitelisting them or overriding the include files turns out to be difficult, as those wrappers are only declared but not defined in the STL headers. Their implementations are not available to Infer so whitelisting them does nothing, and if I provide custom implementations in the headers then normal compilation process will be disrupted because the linker would complain about duplicated implementation.
What I did here is to replace functions whose name matches one of the throw wrapper's name with a `BuiltinDecls.exit`. I have to admit that this is a bit hacky: initially I was trying to do something more general: replacing functions with `noreturn` attribute with `BuitinDecls.exit`. That did not work because, CMIIW, the current frontend only exports function attributes for functions with actual bodies, not declaration-only functions. I'd love to be informed if there are better ways to handle those wrappers.

Reviewed By: jeremydubreil

Differential Revision: D5266030

fbshipit-source-id: 4580227
master
Jia Chen 8 years ago committed by Facebook Github Bot
parent 62cfd554c7
commit f7927cadda

@ -0,0 +1,36 @@
/*
* Copyright (c) 2017 - 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 <functional>
#include <future>
#include <ios>
#include <new>
#include <stdexcept>
#include <typeinfo>
namespace std {
void __throw_bad_alloc() { throw bad_alloc(); }
void __throw_bad_cast() { throw bad_cast(); }
void __throw_bad_exception() { throw bad_exception(); }
void __throw_bad_function_call() { throw bad_function_call(); }
void __throw_bad_typeid() { throw bad_typeid(); }
void __throw_domain_error(const char* s) { throw domain_error(s); }
void __throw_invalid_argument(const char* s) { throw invalid_argument(s); }
void __throw_ios_failure(const char* s) { throw ios_base::failure(s); }
void __throw_length_error(const char* s) { throw length_error(s); }
void __throw_logic_error(const char* s) { throw logic_error(s); }
void __throw_out_of_range(const char* s) { throw out_of_range(s); }
void __throw_overflow_error(const char* s) { throw overflow_error(s); }
void __throw_range_error(const char* s) { throw range_error(s); }
void __throw_runtime_error(const char* s) { throw runtime_error(s); }
void __throw_system_error(int c) {
throw system_error(error_code(c, generic_category()));
}
void __throw_underflow_error(const char* s) { throw underflow_error(s); }
}

@ -19,6 +19,7 @@ codetoanalyze/cpp/errors/memory_leaks/raii_malloc.cpp, memory_leak, 0, MEMORY_LE
codetoanalyze/cpp/errors/models/move.cpp, move::div0_moved_from, 3, DIVIDE_BY_ZERO, [start of procedure move::div0_moved_from(),start of procedure X,return from a call to move::X_X,start of procedure X,return from a call to move::X_X]
codetoanalyze/cpp/errors/models/move.cpp, move::div0_moved_to, 3, DIVIDE_BY_ZERO, [start of procedure move::div0_moved_to(),start of procedure X,return from a call to move::X_X,start of procedure X,return from a call to move::X_X]
codetoanalyze/cpp/errors/models/swap.cpp, swap_null_bad, 4, NULL_DEREFERENCE, [start of procedure swap_null_bad()]
codetoanalyze/cpp/errors/models/throw_wrapper.cpp, nothrow_if_null_bad, 4, NULL_DEREFERENCE, [start of procedure nothrow_if_null_bad(),start of procedure get_null(),return from a call to get_null,Condition is true,start of procedure do_nothing(),return from a call to do_nothing]
codetoanalyze/cpp/errors/mutex/std_mutex.cpp, alarm1, 2, DOUBLE_LOCK, [start of procedure alarm1()]
codetoanalyze/cpp/errors/mutex/std_mutex.cpp, alarm2, 2, DOUBLE_LOCK, [start of procedure alarm2()]
codetoanalyze/cpp/errors/mutex/std_mutex.cpp, alarm2, 2, DOUBLE_LOCK, [start of procedure alarm2()]

@ -0,0 +1,31 @@
/*
* Copyright (c) 2017 - 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.
*/
// std::__throw_bad_alloc() is not a standarized function. It could be defined
// in many places, so we need to consider all possibilities.
#include <new>
#include <stdexcept>
static int* get_null() { return nullptr; }
static void do_nothing() {}
int throw_if_null_ok() {
int* p = get_null();
if (p == nullptr)
std::__throw_bad_alloc();
return *p;
}
int nothrow_if_null_bad() {
int* p = get_null();
if (p == nullptr)
do_nothing();
return *p;
}

@ -358,21 +358,15 @@ digraph iCFG {
"Person#Person#{_ZN6PersonC1ERKS_|constexpr}.723fccb56b807554fd33d1118dcb83e1_2" [label="2: Exit Person_Person \n " color=yellow style=filled]
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_1" [label="1: Start std::bad_exception_bad_exception\nFormals: this:std::bad_exception*\nLocals: \n DECLARE_LOCALS(&return); [line 103]\n " color=yellow style=filled]
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_1" [label="1: Start std::bad_exception_bad_exception\nFormals: this:std::bad_exception*\nLocals: \n " color=yellow style=filled]
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_1" -> "bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_3" ;
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_2" [label="2: Exit std::bad_exception_bad_exception \n " color=yellow style=filled]
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_3" [label="3: Constructor Init \n n$0=*&this:std::bad_exception* [line 103]\n _fun_std::exception_exception(n$0:std::bad_exception*) [line 103]\n " shape="box"]
"exception#exception#std#{_ZNSt9exceptionC1Ev}.5226a0e6cc026fc29eb750a66d588910_1" [label="1: Start std::exception_exception\nFormals: this:std::exception*\nLocals: \n " color=yellow style=filled]
"bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_3" -> "bad_exception#bad_exception#std#{_ZNSt13bad_exceptionC1Ev}.9b3ad9f8b08e34cb77dd347cfc0925a2_2" ;
"exception#exception#std#{_ZNSt9exceptionC1Ev}.5226a0e6cc026fc29eb750a66d588910_1" [label="1: Start std::exception_exception\nFormals: this:std::exception*\nLocals: \n DECLARE_LOCALS(&return); [line 94]\n " color=yellow style=filled]
"exception#exception#std#{_ZNSt9exceptionC1Ev}.5226a0e6cc026fc29eb750a66d588910_1" -> "exception#exception#std#{_ZNSt9exceptionC1Ev}.5226a0e6cc026fc29eb750a66d588910_2" ;
"exception#exception#std#{_ZNSt9exceptionC1Ev}.5226a0e6cc026fc29eb750a66d588910_2" [label="2: Exit std::exception_exception \n " color=yellow style=filled]

Loading…
Cancel
Save