diff --git a/infer/models/cpp/include/infer_model/vector_bufferoverrun.h b/infer/models/cpp/include/infer_model/vector_bufferoverrun.h new file mode 100644 index 000000000..ac4213b3b --- /dev/null +++ b/infer/models/cpp/include/infer_model/vector_bufferoverrun.h @@ -0,0 +1,599 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef INFER_USE_LIBCPP +// libc++ vector header includes it, but it breaks +// compilation with stdlibc++ implementation +#include +#endif + +INFER_NAMESPACE_STD_BEGIN + +struct bool_ref { + bool_ref& operator=(bool x) {} + bool_ref& operator=(const bool_ref& x) {} + + operator bool() const noexcept {} + void flip() noexcept {} + + // not part of C++ std, but required for model implementation to compile + explicit bool_ref(bool x) {} +}; + +template +struct vector_ref { + typedef T& ref; +}; + +template <> +struct vector_ref { + typedef bool_ref ref; +}; + +// this function will be treated as SKIP by infer +template +T* __infer_skip__get_nondet_val() {} + +template +void __infer_deref_first_arg(T* ptr) INFER_MODEL_AS_DEREF_FIRST_ARG; + +// WARNING: do not add any new fields to std::vector model. sizeof(std::vector) +// = 24 !! +template > +class vector { + + public: + typedef vector __self; + typedef _Tp value_type; + typedef _Allocator allocator_type; + typedef allocator_traits __alloc_traits; + typedef typename vector_ref::ref reference; + typedef const value_type& const_reference; + typedef typename __alloc_traits::size_type size_type; + typedef typename __alloc_traits::difference_type difference_type; + typedef typename __alloc_traits::pointer pointer; + typedef typename __alloc_traits::const_pointer const_pointer; + + typedef STD_ITER(pointer, vector) iterator; + typedef STD_ITER(const_pointer, vector) const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + /* INFER SPECIFIC HELPER FUNCTIONS */ + + // required to keep sizeof(std::vector) same as in standard + size_type infer_size = 0; + void* _ignore1; + void* _ignore2; + + void access_at(size_type index) { + _Tp* dummy_array = (_Tp*) malloc(sizeof(value_type) * infer_size); + auto dummy_value = dummy_array[index]; + free(dummy_array); + } + + value_type* get() const { + return __infer_skip__get_nondet_val(); + } + + void allocate(size_type __n) { + infer_size = __n; + } + + void deallocate() { + infer_size = 0; + } + + template + void allocate_iter(Iter begin, Iter end) { + allocate(end - begin); + } + + /* std::vector implementation */ + + vector() noexcept(is_nothrow_default_constructible::value) { + deallocate(); + } + + explicit vector(const allocator_type& __a) noexcept { deallocate(); } + + explicit vector(size_type __n); + // introduced in C++14 + explicit vector(size_type __n, const allocator_type& __a); + vector(size_type __n, const_reference __x); + vector(size_type __n, const_reference __x, const allocator_type& __a); + template + vector(_ForwardIterator __first, + typename enable_if< + is_constructible< + value_type, + typename iterator_traits<_ForwardIterator>::reference>::value, + _ForwardIterator>::type __last); + template + vector(_ForwardIterator __first, + _ForwardIterator __last, + const allocator_type& __a, + typename enable_if::reference>::value>:: + type* = 0); + + vector(initializer_list __il); + + vector(initializer_list __il, const allocator_type& __a); + + vector(const vector& __x); + vector(const vector& __x, const allocator_type& __a); + + vector& operator=(const vector& __x); + + vector(vector&& __x) noexcept; + + vector(vector&& __x, const allocator_type& __a); + + vector& operator=(vector&& __x) noexcept; + /*((__noexcept_move_assign_container<_Allocator, __alloc_traits>::value)); */ + + vector& operator=(initializer_list __il) { + assign(__il.begin(), __il.end()); + return *this; + } + + template + typename enable_if::reference>::value, + void>::type + assign(_ForwardIterator __first, _ForwardIterator __last); + + void assign(size_type __n, const_reference __u); + + void assign(initializer_list __il) { + assign(__il.begin(), __il.end()); + } + + allocator_type get_allocator() const {} + + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + + const_reverse_iterator rbegin() const noexcept { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + + const_reverse_iterator rend() const noexcept { + return const_reverse_iterator(begin()); + } + + const_iterator cbegin() const noexcept { return begin(); } + + const_iterator cend() const noexcept { return end(); } + + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + + const_reverse_iterator crend() const noexcept { return rend(); } + + size_type size() const noexcept { + return infer_size; + } + + size_type capacity() const noexcept {} + + bool empty() const noexcept { return infer_size == 0; } + size_type max_size() const noexcept; + void reserve(size_type __n); + void shrink_to_fit() noexcept; + + reference operator[](size_type __n); + const_reference operator[](size_type __n) const; + reference at(size_type __n); + const_reference at(size_type __n) const; + + reference front() { return (reference)*get(); } + const_reference front() const { return (const_reference)*get(); } + reference back() { return (reference)*get(); } + const_reference back() const { return (const_reference)*get(); } + + value_type* data() noexcept { return get(); } + + const value_type* data() const noexcept { return get(); } + + void push_back(const_reference __x); + void push_back(value_type&& __x); + template + + void emplace_back(_Args&&... __args); + + void pop_back(); + + iterator insert(const_iterator __position, const_reference __x); + iterator insert(const_iterator __position, value_type&& __x); + template + iterator emplace(const_iterator __position, _Args&&... __args); + iterator insert(const_iterator __position, + size_type __n, + const_reference __x); + template + typename enable_if::reference>::value, + iterator>::type + insert(const_iterator __position, + _ForwardIterator __first, + _ForwardIterator __last); + + iterator insert(const_iterator __position, + initializer_list __il) { + return insert(__position, __il.begin(), __il.end()); + } + + iterator erase(const_iterator __position); + iterator erase(const_iterator __first, const_iterator __last); + + void clear() noexcept { deallocate(); } + + void resize(size_type __sz); + void resize(size_type __sz, const_reference __x); + + // NOTE c++17 adds noexcept + void swap(vector&); + + private: + iterator __make_iter(pointer __p) noexcept; + + const_iterator __make_iter(const_pointer __p) const noexcept; +}; + +template +typename vector<_Tp, _Allocator>::size_type vector<_Tp, _Allocator>::max_size() + const noexcept { +} + +template +vector<_Tp, _Allocator>::vector(size_type __n) { + allocate(__n); +} + +template +vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a) { + allocate(__n); +} + +template +vector<_Tp, _Allocator>::vector(size_type __n, const_reference __x) { + allocate(__n); +} + +template +vector<_Tp, _Allocator>::vector(size_type __n, + const_reference __x, + const allocator_type& __a) { + allocate(__n); +} + +template +template +vector<_Tp, _Allocator>::vector( + _ForwardIterator __first, + typename enable_if< + is_constructible< + value_type, + typename iterator_traits<_ForwardIterator>::reference>::value, + _ForwardIterator>::type __last) { + allocate_iter(__first, __last); +} + +template +template +vector<_Tp, _Allocator>::vector( + _ForwardIterator __first, + _ForwardIterator __last, + const allocator_type& __a, + typename enable_if::reference>::value>::type*) { + allocate_iter(__first, __last); +} + +template +vector<_Tp, _Allocator>::vector(const vector& __x) { + allocate(__x.size()); +} + +template +vector<_Tp, _Allocator>::vector(const vector& __x, const allocator_type& __a) { + allocate(__x.size()); +} + +template +inline vector<_Tp, _Allocator>::vector(vector&& __x) noexcept { + allocate(__x.size()); + __x.clear(); +} + +template +inline vector<_Tp, _Allocator>::vector(vector&& __x, + const allocator_type& __a) { + allocate(__x.size()); + __x.clear(); +} + +template +inline vector<_Tp, _Allocator>::vector(initializer_list __il) { + allocate_iter(__il.begin(), __il.end()); +} + +template +inline vector<_Tp, _Allocator>::vector(initializer_list __il, + const allocator_type& __a) { + allocate_iter(__il.begin(), __il.end()); +} + +template +inline vector<_Tp, _Allocator>& vector<_Tp, _Allocator>::operator=( + vector&& __x) noexcept /*((__noexcept_move_assign_container<_Allocator, + __alloc_traits>::value)) */ +{ + allocate(__x.size()); + __x.clear(); + return *this; +} + +template +inline vector<_Tp, _Allocator>& vector<_Tp, _Allocator>::operator=( + const vector& __x) { + allocate(__x.size()); + return *this; +} + +template +template +typename enable_if::reference>::value, + void>::type +vector<_Tp, _Allocator>::assign(_ForwardIterator __first, + _ForwardIterator __last) { + allocate_iter(__first, __last); +} + +template +void vector<_Tp, _Allocator>::assign(size_type __n, const_reference __u) { + allocate(__n); +} + +template +inline typename vector<_Tp, _Allocator>::iterator +vector<_Tp, _Allocator>::__make_iter(pointer __p) noexcept { + return iterator(__p); +} + +template +inline typename vector<_Tp, _Allocator>::const_iterator +vector<_Tp, _Allocator>::__make_iter(const_pointer __p) const noexcept { + return const_iterator(__p); +} + +template +inline typename vector<_Tp, _Allocator>::iterator +vector<_Tp, _Allocator>::begin() noexcept { + return __make_iter(get()); +} + +template +inline typename vector<_Tp, _Allocator>::const_iterator +vector<_Tp, _Allocator>::begin() const noexcept { + return __make_iter(get()); +} + +template +inline typename vector<_Tp, _Allocator>::iterator +vector<_Tp, _Allocator>::end() noexcept { + return __make_iter(get()); +} + +template +inline typename vector<_Tp, _Allocator>::const_iterator +vector<_Tp, _Allocator>::end() const noexcept { + return __make_iter(get()); +} + +template +inline typename vector<_Tp, _Allocator>::reference vector<_Tp, _Allocator>:: +operator[](size_type __n) { + access_at(__n); + return (reference)*get(); +} + +template +inline typename vector<_Tp, _Allocator>::const_reference + vector<_Tp, _Allocator>::operator[](size_type __n) const { + return (const_reference)*get(); +} + +template +typename vector<_Tp, _Allocator>::reference vector<_Tp, _Allocator>::at( + size_type __n) { + access_at(__n); + return (reference)*get(); +} + +template +typename vector<_Tp, _Allocator>::const_reference vector<_Tp, _Allocator>::at( + size_type __n) const { + access_at(__n); + return (const_reference)*get(); +} + +template +void vector<_Tp, _Allocator>::reserve(size_type __n) {} + +template +void vector<_Tp, _Allocator>::shrink_to_fit() noexcept {} + +template +inline void vector<_Tp, _Allocator>::push_back(const_reference __x) { + infer_size++; +} + +template +inline void vector<_Tp, _Allocator>::push_back(value_type&& __x) { + infer_size++; +} + +template +template +inline void vector<_Tp, _Allocator>::emplace_back(_Args&&... __args) { + infer_size++; +} + +template +inline void vector<_Tp, _Allocator>::pop_back() { + infer_size--; +} + +template +inline typename vector<_Tp, _Allocator>::iterator +vector<_Tp, _Allocator>::erase(const_iterator __position) { + infer_size--; + return __position; +} + +template +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::erase( + const_iterator __first, const_iterator __last) { + infer_size -= __last - __first; + return __first; +} + +template +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert( + const_iterator __position, const_reference __x) { + infer_size++; +} + +template +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert( + const_iterator __position, value_type&& __x) { + infer_size++; +} + +template +template +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::emplace( + const_iterator __position, _Args&&... __args) { + infer_size++; +} + +template +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert( + const_iterator __position, size_type __n, const_reference __x) { + infer_size += __n; +} + +template +template +typename enable_if::reference>::value, + typename vector<_Tp, _Allocator>::iterator>::type +vector<_Tp, _Allocator>::insert(const_iterator __position, + _ForwardIterator __first, + _ForwardIterator __last) { + infer_size += __last - __first; +} + +template +void vector<_Tp, _Allocator>::resize(size_type __sz) { + infer_size = __sz; +} + +template +void vector<_Tp, _Allocator>::resize(size_type __sz, const_reference __x) { + infer_size = __sz; +} + +template +void vector<_Tp, _Allocator>::swap(vector& __x) { + auto tmp = __x.size(); + __x.resize(infer_size); + infer_size = tmp; +} + +template +struct hash> + : public unary_function, size_t> { + + size_t operator()(const vector& __vec) const noexcept {} +}; + +template +inline bool operator==(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + const typename vector<_Tp, _Allocator>::size_type __sz = __x.size(); + return __sz == __y.size() && equal(__x.begin(), __x.end(), __y.begin()); +} + +template +inline bool operator!=(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + return !(__x == __y); +} + +template +inline bool operator<(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + return lexicographical_compare( + __x.begin(), __x.end(), __y.begin(), __y.end()); +} + +template +inline bool operator>(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + return __y < __x; +} + +template +inline bool operator>=(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + return !(__x < __y); +} + +template +inline bool operator<=(const vector<_Tp, _Allocator>& __x, + const vector<_Tp, _Allocator>& __y) { + return !(__y < __x); +} + +template +inline void swap(vector<_Tp, _Allocator>& __x, vector<_Tp, _Allocator>& __y) { + __x.swap(__y); +} + +INFER_NAMESPACE_STD_END diff --git a/infer/models/cpp/include/vector b/infer/models/cpp/include/vector index c19ebf900..a88941d98 100644 --- a/infer/models/cpp/include/vector +++ b/infer/models/cpp/include/vector @@ -1,9 +1,16 @@ #include #ifdef INFER_CPP11_ON + +#ifdef __INFER_BUFFEROVERRUN +// Separate model for bufferoverrun checker +// TODO t17807570: move to a separate directory +#include +#else #include +#endif -#else +#else // don't model std::vector pre-c++11 to // simplify implementation #include_next diff --git a/infer/src/clang/ClangCommand.re b/infer/src/clang/ClangCommand.re index 13c947b22..4da779967 100644 --- a/infer/src/clang/ClangCommand.re +++ b/infer/src/clang/ClangCommand.re @@ -115,8 +115,15 @@ let clang_cc1_cmd_sanitizer cmd => { } else { arg }; + let args_defines = + if (Config.bufferoverrun || Config.equal_analyzer Config.analyzer Config.Bufferoverrun) { + ["-D__INFER_BUFFEROVERRUN"] + } else { + [] + }; let post_args_rev = [] |> List.rev_append ["-include", Config.lib_dir ^\/ "clang_wrappers" ^\/ "global_defines.h"] |> + List.rev_append args_defines |> /* Never error on warnings. Clang is often more strict than Apple's version. These arguments are appended at the end to override previous opposite settings. How it's done: suppress all the warnings, since there are no warnings, compiler can't elevate them to error @@ -126,7 +133,7 @@ let clang_cc1_cmd_sanitizer cmd => { fun | [] => /* return non-reversed list */ - List.rev (post_args_rev @ res_rev) + List.rev_append res_rev (List.rev post_args_rev) | [flag, ...tl] when List.mem equal::String.equal flags_blacklist flag => filter_unsupported_args_and_swap_includes (flag, res_rev) tl | [arg, ...tl] => {