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
+ |