Index: www/analyzer/available_checks.html =================================================================== --- www/analyzer/available_checks.html +++ www/analyzer/available_checks.html @@ -43,6 +43,7 @@
+void log(const char *str); + +void test(int value) { + const char *msg = std::to_string(value).c_str(); + // msg points to the buffer of a temporary that is now destroyed + log(msg); // warn: inner pointer of container used after re/deallocation +} +
+nullability.NullableReturnedFromNonnull
+(ObjC)
+Warns when a nullable pointer is returned from a function that has _Nonnull return type. |
+
+ +typedef struct Dummy { int val; } Dummy; + +Dummy *_Nonnull test(Dummy *_Nullable a) { + Dummy *p = a; + return p; // warn +} + |
requestCurrentTaskName
function makes an XPC call and then uses the
+semaphore to block until the XPC call returns (example 1.).+// Example 1. ++ (NSString *)requestCurrentTaskName { + __block NSString *taskName = nil; + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + NSXPCConnection *connection = [[NSXPCConnection alloc] initWithServiceName:@"MyConnection"]; + id remoteObjectProxy = connection.remoteObjectProxy; + [remoteObjectProxy requestCurrentTaskName:^(NSString *task) { + taskName = task; + dispatch_semaphore_signal(sema); + }]; + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + return taskName; +} +
+// Example 2. ++ (NSString *)requestCurrentTaskName { + __block NSString *taskName = nil; + NSXPCConnection *connection = [[NSXPCConnection alloc] initWithServiceName:@"MyConnection"]; + id remoteObjectProxy = [connection synchronousRemoteObjectProxyWithErrorHandler:^(NSError *error) { + NSLog(@"Error = %@", error); + + }]; + [remoteObjectProxy requestCurrentTaskName:^(NSString *task) { + taskName = task; + }]; + return taskName; +} +
+class PaddedA { // warn: excessive padding + char c1; + int i; + char c2; +}; +
+void *f(int n) { + return malloc(n * 0 * sizeof(int)); // warn: Call to 'malloc' has an + // allocation size of 0 bytes +} +
@synchronized
.@synchronized
.
+
void test(id x) { @@ -748,6 +878,38 @@
NSError **
) are __autoreleasing
. Writing to such
+parameters inside autoreleasing pools might crash whenever the parameter
+outlives the pool. Detecting such crashes may be difficult, as usage of
+autorelease pool is usually hidden inside the called functions implementation.
++BOOL writeToErrorWithIterator(NSError *__autoreleasing* error, NSArray *a) { [a enumerateObjectsUsingBlock:^{ + *error = [NSError errorWithDomain:1]; + }]; +} +
+BOOL writeToErrorInBlockFromCFunc(NSError *__autoreleasing* error) { + dispatch_semaphore_t sem = dispatch_semaphore_create(0l); + dispatch_async(queue, ^{ + if (error) { + *error = [NSError errorWithDomain:1]; + } + dispatch_semaphore_signal(sem); + }); + + dispatch_semaphore_wait(sem, 100); + return 0; +} +
[[NSRunLoop mainRunLoop] run]
in
+ the same autorelease pool.[[NSRunLoop mainRunLoop] run]
in
+ no autorelease pool.+ +
Name, Description | Example |
+valist.CopyToSelf
+(C)
+Calls to the va_copy macro should not copy onto itself. |
+
+ +#include <stdarg.h> + +void test(int x, ...) { + va_list args; + va_start(args, x); + va_copy(args, args); // warn + va_end(args); +} + |
+valist.Uninitialized
+(C)
+Calls to the va_arg , va_copy , or
+va_end macro must happen after calling va_start and
+before calling va_end . |
+
+ +#include <stdarg.h> + +void test(int x, ...) { + va_list args; + int y = va_arg(args, int); // warn +} + +#include <stdarg.h> + +void test(int x, ...) { + va_list args; + va_start(args, x); + va_end(args); + int z = va_arg(args, int); // warn +} + |
+valist.Unterminated
+(C)
+Every va_start must be matched by a va_end . A va_list
+can only be ended once. |
+
+ +#include <stdarg.h> + +void test(int x, ...) { + va_list args; + va_start(args, x); + int y = x + va_arg(args, int); +} // warn: missing va_end + |