diff options
| author | Devin Coughlin <dcoughlin@apple.com> | 2016-02-07 16:55:44 +0000 |
|---|---|---|
| committer | Devin Coughlin <dcoughlin@apple.com> | 2016-02-07 16:55:44 +0000 |
| commit | 9165df129e2d5663b3249c74fad9af677e7c80ef (patch) | |
| tree | b1a2dd1dda2e4b6145ef2b880d6df6fe313ca978 /clang/test | |
| parent | 656b3b4c5d9bb801579351df798f4d984502c364 (diff) | |
| download | bcm5719-llvm-9165df129e2d5663b3249c74fad9af677e7c80ef.tar.gz bcm5719-llvm-9165df129e2d5663b3249c74fad9af677e7c80ef.zip | |
[analyzer] Invalidate destination of std::copy() and std::copy_backward().
Now that the libcpp implementations of these methods has a branch that doesn't call
memmove(), the analyzer needs to invalidate the destination for these methods explicitly.
rdar://problem/23575656
llvm-svn: 260043
Diffstat (limited to 'clang/test')
| -rw-r--r-- | clang/test/Analysis/Inputs/system-header-simulator-cxx.h | 118 | ||||
| -rw-r--r-- | clang/test/Analysis/bstring.cpp | 38 | ||||
| -rw-r--r-- | clang/test/Analysis/diagnostics/explicit-suppression.cpp | 12 |
3 files changed, 162 insertions, 6 deletions
diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h index f9049c3ae9e..f6b970088ea 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -7,6 +7,9 @@ typedef unsigned char uint8_t; +typedef __typeof__(sizeof(int)) size_t; +void *memmove(void *s1, const void *s2, size_t n); + namespace std { template <class T1, class T2> struct pair { @@ -104,11 +107,120 @@ namespace std { const _E* end() const {return __begin_ + __size_;} }; + template <bool, class _Tp = void> struct enable_if {}; + template <class _Tp> struct enable_if<true, _Tp> {typedef _Tp type;}; + + template <class _Tp, _Tp __v> + struct integral_constant + { + static const _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant type; + + operator value_type() const {return value;} + + value_type operator ()() const {return value;} + }; + + template <class _Tp, _Tp __v> + const _Tp integral_constant<_Tp, __v>::value; + + template <class _Tp, class _Arg> + struct is_trivially_assignable + : integral_constant<bool, __is_trivially_assignable(_Tp, _Arg)> + { + }; + + typedef integral_constant<bool,true> true_type; + typedef integral_constant<bool,false> false_type; + + template <class _Tp> struct is_const : public false_type {}; + template <class _Tp> struct is_const<_Tp const> : public true_type {}; + + template <class _Tp> struct is_reference : public false_type {}; + template <class _Tp> struct is_reference<_Tp&> : public true_type {}; + + template <class _Tp, class _Up> struct is_same : public false_type {}; + template <class _Tp> struct is_same<_Tp, _Tp> : public true_type {}; + + template <class _Tp, bool = is_const<_Tp>::value || is_reference<_Tp>::value > + struct __add_const {typedef _Tp type;}; + + template <class _Tp> + struct __add_const<_Tp, false> {typedef const _Tp type;}; + + template <class _Tp> struct add_const {typedef typename __add_const<_Tp>::type type;}; + + template <class _Tp> struct remove_const {typedef _Tp type;}; + template <class _Tp> struct remove_const<const _Tp> {typedef _Tp type;}; + + template <class _Tp> struct add_lvalue_reference {typedef _Tp& type;}; + + template <class _Tp> struct is_trivially_copy_assignable + : public is_trivially_assignable<typename add_lvalue_reference<_Tp>::type, + typename add_lvalue_reference<typename add_const<_Tp>::type>::type> {}; + + template<class InputIter, class OutputIter> + OutputIter __copy(InputIter II, InputIter IE, OutputIter OI) { + while (II != IE) + *OI++ = *II++; + + return OI; + } + + template <class _Tp, class _Up> + inline + typename enable_if + < + is_same<typename remove_const<_Tp>::type, _Up>::value && + is_trivially_copy_assignable<_Up>::value, + _Up* + >::type __copy(_Tp* __first, _Tp* __last, _Up* __result) { + size_t __n = __last - __first; + + if (__n > 0) + memmove(__result, __first, __n * sizeof(_Up)); + + return __result + __n; + } + template<class InputIter, class OutputIter> OutputIter copy(InputIter II, InputIter IE, OutputIter OI) { - while (II != IE) - *OI++ = *II++; - return OI; + return __copy(II, IE, OI); + } + + template <class _BidirectionalIterator, class _OutputIterator> + inline + _OutputIterator + __copy_backward(_BidirectionalIterator __first, _BidirectionalIterator __last, + _OutputIterator __result) + { + while (__first != __last) + *--__result = *--__last; + return __result; + } + + template <class _Tp, class _Up> + inline + typename enable_if + < + is_same<typename remove_const<_Tp>::type, _Up>::value && + is_trivially_copy_assignable<_Up>::value, + _Up* + >::type __copy_backward(_Tp* __first, _Tp* __last, _Up* __result) { + size_t __n = __last - __first; + + if (__n > 0) + { + __result -= __n; + memmove(__result, __first, __n * sizeof(_Up)); + } + return __result; + } + + template<class InputIter, class OutputIter> + OutputIter copy_backward(InputIter II, InputIter IE, OutputIter OI) { + return __copy_backward(II, IE, OI); } struct input_iterator_tag { }; diff --git a/clang/test/Analysis/bstring.cpp b/clang/test/Analysis/bstring.cpp new file mode 100644 index 00000000000..0b4e7e94f00 --- /dev/null +++ b/clang/test/Analysis/bstring.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s + +#include "Inputs/system-header-simulator-cxx.h" +#include "Inputs/system-header-simulator-for-malloc.h" + +void clang_analyzer_eval(int); + +int *testStdCopyInvalidatesBuffer(std::vector<int> v) { + int n = v.size(); + int *buf = (int *)malloc(n * sizeof(int)); + + buf[0] = 66; + + // Call to copy should invalidate buf. + std::copy(v.begin(), v.end(), buf); + + int i = buf[0]; + + clang_analyzer_eval(i == 66); // expected-warning {{UNKNOWN}} + + return buf; +} + +int *testStdCopyBackwardInvalidatesBuffer(std::vector<int> v) { + int n = v.size(); + int *buf = (int *)malloc(n * sizeof(int)); + + buf[0] = 66; + + // Call to copy_backward should invalidate buf. + std::copy_backward(v.begin(), v.end(), buf + n); + + int i = buf[0]; + + clang_analyzer_eval(i == 66); // expected-warning {{UNKNOWN}} + + return buf; +} diff --git a/clang/test/Analysis/diagnostics/explicit-suppression.cpp b/clang/test/Analysis/diagnostics/explicit-suppression.cpp index 78067573e32..67a47d02b6e 100644 --- a/clang/test/Analysis/diagnostics/explicit-suppression.cpp +++ b/clang/test/Analysis/diagnostics/explicit-suppression.cpp @@ -9,9 +9,15 @@ void clang_analyzer_eval(bool); -void testCopyNull(int *I, int *E) { - std::copy(I, E, (int *)0); +class C { + // The virtual function is to make C not trivially copy assignable so that we call the + // variant of std::copy() that does not defer to memmove(). + virtual int f(); +}; + +void testCopyNull(C *I, C *E) { + std::copy(I, E, (C *)0); #ifndef SUPPRESSED - // expected-warning@../Inputs/system-header-simulator-cxx.h:110 {{Dereference of null pointer}} + // expected-warning@../Inputs/system-header-simulator-cxx.h:166 {{Called C++ object pointer is null}} #endif } |

