diff options
Diffstat (limited to 'clang/test/Analysis')
14 files changed, 423 insertions, 21 deletions
diff --git a/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm index 104b555..8aad838 100644 --- a/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm +++ b/clang/test/Analysis/Checkers/WebKit/forward-decl-checker.mm @@ -11,6 +11,8 @@ class Obj; Obj* provide_obj_ptr(); void receive_obj_ptr(Obj* p = nullptr); +void receive_obj_ref(Obj&); +void receive_obj_rref(Obj&&); sqlite3* open_db(); void close_db(sqlite3*); @@ -38,6 +40,16 @@ Obj& ref() { return obj; } +void opaque_call_arg(Obj* obj, Obj&& otherObj, const RefPtr<Obj>& safeObj, WeakPtr<Obj> weakObj, std::unique_ptr<Obj>& uniqObj) { + receive_obj_ref(*obj); + receive_obj_ptr(&*obj); + receive_obj_rref(std::move(otherObj)); + receive_obj_ref(*safeObj.get()); + receive_obj_ptr(weakObj.get()); + // expected-warning@-1{{Call argument for parameter 'p' uses a forward declared type 'Obj *'}} + receive_obj_ref(*uniqObj); +} + Obj&& provide_obj_rval(); void receive_obj_rval(Obj&& p); diff --git a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h index 1e44de8..d55b3ab 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-system-header.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-system-header.h @@ -34,6 +34,8 @@ void os_log_msg(os_log_t oslog, os_log_type_t type, const char *msg, ...); typedef const struct __attribute__((objc_bridge(NSString))) __CFString * CFStringRef; +extern CFStringRef const kCFURLTagNamesKey; + #ifdef __OBJC__ @class NSString; @interface SystemObject { @@ -41,4 +43,8 @@ typedef const struct __attribute__((objc_bridge(NSString))) __CFString * CFStrin CFStringRef cf_string; } @end + +typedef NSString *NSNotificationName; +extern "C" NSNotificationName NSApplicationDidBecomeActiveNotification; + #endif diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index a49faa1..7055a94 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -25,23 +25,23 @@ namespace std { template <typename T> class unique_ptr { private: - T *t; + void *t; public: unique_ptr() : t(nullptr) { } unique_ptr(T *t) : t(t) { } ~unique_ptr() { if (t) - delete t; + delete static_cast<T*>(t); } template <typename U> unique_ptr(unique_ptr<U>&& u) : t(u.t) { u.t = nullptr; } - T *get() const { return t; } - T *operator->() const { return t; } - T &operator*() const { return *t; } + T *get() const { return static_cast<T*>(t); } + T *operator->() const { return get(); } + T &operator*() const { return *get(); } unique_ptr &operator=(T *) { return *this; } explicit operator bool() const { return !!t; } }; @@ -313,4 +313,90 @@ public: UniqueRef &operator=(T &) { return *this; } }; +class WeakPtrImpl { +private: + void* ptr { nullptr }; + mutable unsigned m_refCount { 0 }; + + template <typename U> friend class CanMakeWeakPtr; + template <typename U> friend class WeakPtr; + +public: + template <typename T> + static Ref<WeakPtrImpl> create(T& t) + { + return adoptRef(*new WeakPtrImpl(t)); + } + + void ref() const { m_refCount++; } + void deref() const { + m_refCount--; + if (!m_refCount) + delete const_cast<WeakPtrImpl*>(this); + } + + template <typename T> + T* get() { return static_cast<T*>(ptr); } + operator bool() const { return !!ptr; } + void clear() { ptr = nullptr; } + +private: + template <typename T> + WeakPtrImpl(T* t) + : ptr(static_cast<void*>(t)) + { } +}; + +template <typename T> +class CanMakeWeakPtr { +private: + RefPtr<WeakPtrImpl> impl; + + template <typename U> friend class CanMakeWeakPtr; + template <typename U> friend class WeakPtr; + + Ref<WeakPtrImpl> createWeakPtrImpl() { + if (!impl) + impl = WeakPtrImpl::create(static_cast<T>(*this)); + return *impl; + } + +public: + ~CanMakeWeakPtr() { + if (!impl) + return; + impl->clear(); + impl = nullptr; + } +}; + +template <typename T> +class WeakPtr { +private: + RefPtr<WeakPtrImpl> impl; + +public: + WeakPtr(T& t) { + *this = t; + } + WeakPtr(T* t) { + *this = t; + } + + template <typename U> + WeakPtr<T> operator=(U& obj) { + impl = obj.createWeakPtrImpl(); + } + + template <typename U> + WeakPtr<T> operator=(U* obj) { + impl = obj ? obj->createWeakPtrImpl() : nullptr; + } + + T* get() { + return impl ? impl->get<T>() : nullptr; + } + +}; + #endif diff --git a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h index a5fc3d7..edf4011 100644 --- a/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/objc-mock-types.h @@ -98,12 +98,20 @@ typedef CVImageBufferRef CVPixelBufferRef; typedef signed int CVReturn; CVReturn CVPixelBufferCreateWithIOSurface(CFAllocatorRef allocator, IOSurfaceRef surface, CFDictionaryRef pixelBufferAttributes, CF_RETURNS_RETAINED CVPixelBufferRef * pixelBufferOut); +extern "C" NSString *NSStringFromSelector(SEL aSelector); +extern "C" SEL NSSelectorFromString(NSString *aSelectorName); + +extern "C" NSString *NSStringFromClass(Class aClass); +extern "C" Class NSClassFromString(NSString *aClassName); + +extern "C" NSString *NSStringFromProtocol(Protocol *proto); +extern "C" Protocol * NSProtocolFromString(NSString *namestr); + CFRunLoopRef CFRunLoopGetCurrent(void); CFRunLoopRef CFRunLoopGetMain(void); extern CFTypeRef CFRetain(CFTypeRef cf); extern void CFRelease(CFTypeRef cf); #define CFSTR(cStr) ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr "")) -extern Class NSClassFromString(NSString *aClassName); #if __has_feature(objc_arc) id CFBridgingRelease(CFTypeRef X) { diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm index a517dbc..8bef24f 100644 --- a/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm +++ b/clang/test/Analysis/Checkers/WebKit/unretained-call-args.mm @@ -567,6 +567,64 @@ struct Derived : Base { } // namespace ns_retained_return_value +namespace autoreleased { + +NSString *provideAutoreleased() __attribute__((ns_returns_autoreleased)); +void consume(NSString *); + +void foo() { + consume(provideAutoreleased()); +} + +} // autoreleased + +namespace sel_string { + +void consumeStr(NSString *); +void consumeSel(SEL); +void consumeClass(Class); +void consumeProtocol(Protocol *); + +void foo() { + consumeStr(NSStringFromSelector(@selector(mutableCopy))); + consumeSel(NSSelectorFromString(@"mutableCopy")); + consumeStr(NSStringFromClass(NSNumber.class)); + consumeClass(NSClassFromString(@"NSNumber")); + consumeStr(NSStringFromProtocol(@protocol(NSCopying))); + consumeProtocol(NSProtocolFromString(@"NSCopying")); +} + +} // namespace sel_string + +namespace template_function { + +class Base { +public: + virtual ~Base() = default; + void send(dispatch_queue_t) const; + void ref() const; + void deref() const; +}; + +template<typename Traits> +class Derived : public Base { +public: + virtual ~Derived() = default; + + void send(typename Traits::MessageType) const; + + virtual OSObjectPtr<dispatch_queue_t> msg(typename Traits::MessageType) const = 0; +}; + +template<typename Traits> +void Derived<Traits>::send(typename Traits::MessageType messageType) const +{ + OSObjectPtr dictionary = msg(messageType); + Base::send(dictionary.get()); +} + +} // namespace template_function + @interface TestObject : NSObject - (void)doWork:(NSString *)msg, ...; - (void)doWorkOnSelf; diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm index 307a4d03..f49e7bd 100644 --- a/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm +++ b/clang/test/Analysis/Checkers/WebKit/unretained-local-vars.mm @@ -1,8 +1,11 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedLocalVarsChecker -verify %s #import "objc-mock-types.h" +#import "mock-system-header.h" void someFunction(); +extern "C" CFStringRef LocalGlobalCFString; +extern "C" NSString *LocalGlobalNSString; namespace raw_ptr { void foo() { @@ -535,6 +538,41 @@ unsigned foo() { } // namespace ns_retained_return_value +namespace autoreleased { + +NSString *provideAutoreleased() __attribute__((ns_returns_autoreleased)); +void consume(NSString *); + +void foo() { + auto *string = provideAutoreleased(); + consume(string); +} + +} // autoreleased + +namespace ns_global { + +void consumeCFString(CFStringRef); +void consumeNSString(NSString *); + +void cf() { + auto *str = kCFURLTagNamesKey; + consumeCFString(str); + auto *localStr = LocalGlobalCFString; + // expected-warning@-1{{Local variable 'localStr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}} + consumeCFString(localStr); +} + +void ns() { + auto *str = NSApplicationDidBecomeActiveNotification; + consumeNSString(str); + auto *localStr = LocalGlobalNSString; + // expected-warning@-1{{Local variable 'localStr' is unretained and unsafe [alpha.webkit.UnretainedLocalVarsChecker]}} + consumeNSString(localStr); +} + +} + bool doMoreWorkOpaque(OtherObj*); SomeObj* provide(); diff --git a/clang/test/Analysis/Checkers/WebKit/unretained-obj-arg.mm b/clang/test/Analysis/Checkers/WebKit/unretained-obj-arg.mm new file mode 100644 index 0000000..5c78b21 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/unretained-obj-arg.mm @@ -0,0 +1,18 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedCallArgsChecker -verify %s + +#import "mock-types.h" +#import "mock-system-header.h" + +void consumeCFString(CFStringRef); +extern "C" CFStringRef LocalGlobalCFString; +void consumeNSString(NSString *); +extern "C" NSString *LocalGlobalNSString; + +void foo() { + consumeCFString(kCFURLTagNamesKey); + consumeCFString(LocalGlobalCFString); + // expected-warning@-1{{Call argument is unretained and unsafe}} + consumeNSString(NSApplicationDidBecomeActiveNotification); + consumeNSString(LocalGlobalNSString); + // expected-warning@-1{{Call argument is unretained and unsafe}} +} diff --git a/clang/test/Analysis/analyzer-enabled-checkers.c b/clang/test/Analysis/analyzer-enabled-checkers.c index 0092331..bfe418b 100644 --- a/clang/test/Analysis/analyzer-enabled-checkers.c +++ b/clang/test/Analysis/analyzer-enabled-checkers.c @@ -19,6 +19,7 @@ // CHECK-NEXT: core.NonNullParamChecker // CHECK-NEXT: core.NonnilStringConstants // CHECK-NEXT: core.NullDereference +// CHECK-NEXT: core.NullPointerArithm // CHECK-NEXT: core.StackAddressEscape // CHECK-NEXT: core.UndefinedBinaryOperatorResult // CHECK-NEXT: core.VLASize diff --git a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp index 9cbe045..2a0caad 100644 --- a/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp +++ b/clang/test/Analysis/analyzer-stats/entry-point-stats.cpp @@ -8,6 +8,13 @@ // CHECK-NEXT: "c:@F@fib#i#": { // CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp", // CHECK-NEXT: "DebugName": "fib(unsigned int)", +// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}", +// CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}", +// CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}", +// CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}", +// CHECK-NEXT: "MaxReachableSize": "{{[0-9]+}}", +// CHECK-NEXT: "MaxTimeSpentSolvingZ3Queries": "{{[0-9]+}}", +// CHECK-NEXT: "MaxValidBugClassSize": "{{[0-9]+}}", // CHECK-NEXT: "NumBlocks": "{{[0-9]+}}", // CHECK-NEXT: "NumBlocksUnreachable": "{{[0-9]+}}", // CHECK-NEXT: "NumCTUSteps": "{{[0-9]+}}", @@ -33,18 +40,18 @@ // CHECK-NEXT: "NumTimesZ3SpendsTooMuchTimeOnASingleEQClass": "{{[0-9]+}}", // CHECK-NEXT: "NumTimesZ3TimedOut": "{{[0-9]+}}", // CHECK-NEXT: "NumZ3QueriesDone": "{{[0-9]+}}", -// CHECK-NEXT: "TimeSpentSolvingZ3Queries": "{{[0-9]+}}", +// CHECK-NEXT: "TimeSpentSolvingZ3Queries": "{{[0-9]+}}" +// CHECK-NEXT: }, +// CHECK-NEXT: "c:@F@main#I#**C#": { +// CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp", +// CHECK-NEXT: "DebugName": "main(int, char **)", +// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}", // CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxReachableSize": "{{[0-9]+}}", // CHECK-NEXT: "MaxTimeSpentSolvingZ3Queries": "{{[0-9]+}}", // CHECK-NEXT: "MaxValidBugClassSize": "{{[0-9]+}}", -// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}" -// CHECK-NEXT: }, -// CHECK-NEXT: "c:@F@main#I#**C#": { -// CHECK-NEXT: "File": "{{.*}}entry-point-stats.cpp", -// CHECK-NEXT: "DebugName": "main(int, char **)", // CHECK-NEXT: "NumBlocks": "{{[0-9]+}}", // CHECK-NEXT: "NumBlocksUnreachable": "{{[0-9]+}}", // CHECK-NEXT: "NumCTUSteps": "{{[0-9]+}}", @@ -70,14 +77,7 @@ // CHECK-NEXT: "NumTimesZ3SpendsTooMuchTimeOnASingleEQClass": "{{[0-9]+}}", // CHECK-NEXT: "NumTimesZ3TimedOut": "{{[0-9]+}}", // CHECK-NEXT: "NumZ3QueriesDone": "{{[0-9]+}}", -// CHECK-NEXT: "TimeSpentSolvingZ3Queries": "{{[0-9]+}}", -// CHECK-NEXT: "MaxBugClassSize": "{{[0-9]+}}", -// CHECK-NEXT: "MaxCFGSize": "{{[0-9]+}}", -// CHECK-NEXT: "MaxQueueSize": "{{[0-9]+}}", -// CHECK-NEXT: "MaxReachableSize": "{{[0-9]+}}", -// CHECK-NEXT: "MaxTimeSpentSolvingZ3Queries": "{{[0-9]+}}", -// CHECK-NEXT: "MaxValidBugClassSize": "{{[0-9]+}}", -// CHECK-NEXT: "PathRunningTime": "{{[0-9]+}}" +// CHECK-NEXT: "TimeSpentSolvingZ3Queries": "{{[0-9]+}}" // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NOT: non_entry_point diff --git a/clang/test/Analysis/loc-folding.cpp b/clang/test/Analysis/loc-folding.cpp new file mode 100644 index 0000000..1fcb066 --- /dev/null +++ b/clang/test/Analysis/loc-folding.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_analyze_cc1 -verify %s -analyzer-config eagerly-assume=false \ +// RUN: -analyzer-checker=core,debug.ExprInspection + +void clang_analyzer_eval(bool); + +void element_constant() { + char arr[10]; + clang_analyzer_eval(arr + 1 > arr); // expected-warning{{TRUE}} +} + +void element_known() { + char arr[10]; + int off = 1; + clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}} +} + +void element_constrained(int off) { + char arr[10]; + if (off == 1) { + clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}} + } +} + +void element_unknown(int off) { + char arr[10]; + clang_analyzer_eval(arr + off > arr); // expected-warning{{UNKNOWN}} +} + +void element_complex(int off) { + char arr[10]; + int comp = off * 2; + if (off == 1) { + clang_analyzer_eval(arr + comp); // expected-warning{{TRUE}} + } +} + +void base_constant(int *arr) { + clang_analyzer_eval(arr + 1 > arr); // expected-warning{{TRUE}} +} + +void base_known(int *arr) { + int off = 1; + clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}} +} + +void base_constrained(int *arr, int off) { + if (off == 1) { + clang_analyzer_eval(arr + off > arr); // expected-warning{{TRUE}} + } +} + +void base_unknown(int *arr, int off) { + clang_analyzer_eval(arr + off > arr); // expected-warning{{UNKNOWN}} +} + +void base_complex(int *arr, int off) { + int comp = off * 2; + if (off == 1) { + clang_analyzer_eval(arr + comp > arr); // expected-warning{{TRUE}} + } +} diff --git a/clang/test/Analysis/null-pointer-arithm.c b/clang/test/Analysis/null-pointer-arithm.c new file mode 100644 index 0000000..2288247 --- /dev/null +++ b/clang/test/Analysis/null-pointer-arithm.c @@ -0,0 +1,76 @@ +// RUN: %clang_analyze_cc1 -verify %s \ +// RUN: -analyzer-checker=core + +extern int *get_pointer(); + +int *test_add1(int offset) { + int *p = get_pointer(); + if (p) {} + return p + offset; // expected-warning{{Addition of a null pointer (from variable 'p') and a probably nonzero integer value (from variable 'offset') may result in undefined behavior}} +} + +int *test_add2(int offset) { + int *p = get_pointer(); + if (p) {} + if (offset) {} + return p + offset; // expected-warning{{Addition of a null pointer (from variable 'p') and a nonzero integer value (from variable 'offset') results in undefined behavior}} +} + +int *test_add3(int offset) { + int *p = get_pointer(); + if (p) {} + if (offset != 0) return 0; + return p + offset; +} + +int *test_add4(int offset) { + int *p = get_pointer(); + if (p) {} + if (offset == 0) return 0; + return p + offset; // expected-warning{{Addition of a null pointer (from variable 'p') and a nonzero integer value (from variable 'offset') results in undefined behavior}} +} + +int *test_add5(int offset) { + int *p = get_pointer(); + if (p) {} + return offset + p; // expected-warning{{Addition of a probably nonzero integer value (from variable 'offset') and a null pointer (from variable 'p') may result in undefined behavior}} +} + +int *test_sub1(int offset) { + int *p = get_pointer(); + if (p) {} + return p - offset; // expected-warning{{Subtraction of a null pointer (from variable 'p') and a probably nonzero integer value (from variable 'offset') may result in undefined behavior}} +} + +int test_sub_p1() { + int *p = get_pointer(); + if (p) {} + return p - p; +} + +int test_sub_p2() { + int *p1 = get_pointer(); + int *p2 = get_pointer(); + if (p1) {} + if (p2) {} + return p1 - p2; + // expected-warning@-1{{Subtraction of a non-null pointer (from variable 'p1') and a null pointer (from variable 'p2') results in undefined behavior}} + // expected-warning@-2{{Subtraction of a null pointer (from variable 'p1') and a non-null pointer (from variable 'p2') results in undefined behavior}} +} + +int test_sub_p3() { + int *p1 = get_pointer(); + int *p2 = get_pointer(); + if (p1) {} + return p1 - p2; // expected-warning{{Subtraction of a null pointer (from variable 'p1') and a probably non-null pointer (from variable 'p2') may result in undefined behavior}} +} + +struct S { + char *p; + int offset; +}; + +char *test_struct(struct S s) { + if (s.p) {} + return s.p + s.offset; // expected-warning{{Addition of a null pointer (via field 'p') and a probably nonzero integer value (via field 'offset') may result in undefined behavior}} +} diff --git a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c index 7fae958..9b32960 100644 --- a/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c +++ b/clang/test/Analysis/std-c-library-functions-arg-enabled-checkers.c @@ -27,6 +27,7 @@ // CHECK-NEXT: core.NonNullParamChecker // CHECK-NEXT: core.NonnilStringConstants // CHECK-NEXT: core.NullDereference +// CHECK-NEXT: core.NullPointerArithm // CHECK-NEXT: core.StackAddressEscape // CHECK-NEXT: core.UndefinedBinaryOperatorResult // CHECK-NEXT: core.VLASize diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c index cdd3627..9d24583 100644 --- a/clang/test/Analysis/string.c +++ b/clang/test/Analysis/string.c @@ -82,16 +82,21 @@ size_t strlen(const char *s); void strlen_constant0(void) { clang_analyzer_eval(strlen("123") == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(&("123"[1])) == 2); // expected-warning{{TRUE}} } void strlen_constant1(void) { const char *a = "123"; clang_analyzer_eval(strlen(a) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(a + 1) == 2); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(a + 3) == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(a + 4)); // expected-warning{{UNKNOWN}} } void strlen_constant2(char x) { char a[] = "123"; clang_analyzer_eval(strlen(a) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(a + 1) == 2); // expected-warning{{UNKNOWN}} a[0] = x; clang_analyzer_eval(strlen(a) == 3); // expected-warning{{UNKNOWN}} @@ -105,10 +110,12 @@ char global_non_const_arr[] = "op"; void strlen_global_constant_ptr(void) { clang_analyzer_eval(strlen(global_str_ptr) == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(global_str_ptr + 1) == 3); // expected-warning{{TRUE}} } void strlen_global_constant_arr(void) { clang_analyzer_eval(strlen(global_str_arr) == 4); // expected-warning{{TRUE}} + clang_analyzer_eval(strlen(global_str_arr + 1) == 3); // expected-warning{{TRUE}} } void strlen_global_non_const_ptr(void) { @@ -235,6 +242,17 @@ void testStrlenCallee(void) { clang_analyzer_eval(lenBefore == lenAfter); // expected-warning{{UNKNOWN}} } +void strlen_symbolic_offset(unsigned x) { + const char *str = "abcd"; + if (x < 1 || x > 3) + return; + // FIXME: these should be TRUE + clang_analyzer_eval(strlen(str + x) >= 1); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(strlen(str + x) <= 3); // expected-warning{{UNKNOWN}} + if (x != 1) + return; + clang_analyzer_eval(strlen(str + x) == 3); // expected-warning{{TRUE}} +} //===----------------------------------------------------------------------=== // strnlen() @@ -244,32 +262,38 @@ size_t strnlen(const char *s, size_t maxlen); void strnlen_constant0(void) { clang_analyzer_eval(strnlen("123", 10) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(&("123"[1]), 10) == 2); // expected-warning{{TRUE}} } void strnlen_constant1(void) { const char *a = "123"; clang_analyzer_eval(strnlen(a, 10) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(a + 1, 10) == 2); // expected-warning{{TRUE}} } void strnlen_constant2(char x) { char a[] = "123"; clang_analyzer_eval(strnlen(a, 10) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(a + 1, 10) == 2); // expected-warning{{UNKNOWN}} a[0] = x; clang_analyzer_eval(strnlen(a, 10) == 3); // expected-warning{{UNKNOWN}} } void strnlen_constant4(void) { clang_analyzer_eval(strnlen("123456", 3) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(&("123456"[1]), 3) == 3); // expected-warning{{TRUE}} } void strnlen_constant5(void) { const char *a = "123456"; clang_analyzer_eval(strnlen(a, 3) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(a + 1, 3) == 3); // expected-warning{{TRUE}} } void strnlen_constant6(char x) { char a[] = "123456"; clang_analyzer_eval(strnlen(a, 3) == 3); // expected-warning{{TRUE}} + clang_analyzer_eval(strnlen(a + 1, 3) == 3); // expected-warning{{UNKNOWN}} a[0] = x; clang_analyzer_eval(strnlen(a, 3) == 3); // expected-warning{{UNKNOWN}} } @@ -326,6 +350,19 @@ void strnlen_at_actual(size_t limit) { } } +void strnlen_at_actual_1(size_t limit) { + const char *str = "abc"; + size_t len = strnlen(str + 1, limit); + clang_analyzer_eval(len <= 2); // expected-warning{{TRUE}} + // This is due to eager assertion in strnlen. + if (limit == 0) { + clang_analyzer_eval(len == 0); // expected-warning{{TRUE}} + } else { + clang_analyzer_eval(len == 2); // expected-warning{{UNKNOWN}} + clang_analyzer_eval(len < 2); // expected-warning{{UNKNOWN}} + } +} + //===----------------------------------------------------------------------=== // strcpy() //===----------------------------------------------------------------------=== diff --git a/clang/test/Analysis/zero-size-non-pod-array.cpp b/clang/test/Analysis/zero-size-non-pod-array.cpp index 628be0d7..8a32a49 100644 --- a/clang/test/Analysis/zero-size-non-pod-array.cpp +++ b/clang/test/Analysis/zero-size-non-pod-array.cpp @@ -95,7 +95,7 @@ void zeroSizeArrayBinding() { // Note: This is an error in gcc but a warning in clang. // In MSVC the declaration of 'S arr[0]' is already an error // and it doesn't recognize this syntax as a structured binding. - auto [] = arr; //expected-warning{{ISO C++17 does not allow a decomposition group to be empty}} + auto [] = arr; //expected-warning{{ISO C++17 does not allow a structured binding group to be empty}} clang_analyzer_eval(S::CtorInvocationCount == 0); //expected-warning{{TRUE}} } |