diff --git a/infer/src/clang/cTrans_models.ml b/infer/src/clang/cTrans_models.ml index 2ecf1f588..6f0efbb68 100644 --- a/infer/src/clang/cTrans_models.ml +++ b/infer/src/clang/cTrans_models.ml @@ -214,6 +214,8 @@ let dispatch_functions = [ ("dispatch_group_notify", 2); ("dispatch_group_wait", 2); ("dispatch_barrier_async", 1); + ("dispatch_source_set_cancel_handler", 1); + ("dispatch_source_set_event_handler", 1); ] let is_dispatch_function_name function_name = diff --git a/infer/tests/codetoanalyze/objc/errors/Makefile b/infer/tests/codetoanalyze/objc/errors/Makefile index 14edd1f2d..e6c8fb353 100644 --- a/infer/tests/codetoanalyze/objc/errors/Makefile +++ b/infer/tests/codetoanalyze/objc/errors/Makefile @@ -39,6 +39,7 @@ SOURCES_DEFAULT = \ procdescs/MethodCall.m \ property/main.c \ resource_leaks/ResourceLeakExample.m \ + resource_leaks/Dispatch_sources.m \ shared/block/block-it.m \ shared/block/dispatch.m \ shared/category_procdesc/EOCPerson.m \ diff --git a/infer/tests/codetoanalyze/objc/errors/issues.exp b/infer/tests/codetoanalyze/objc/errors/issues.exp index 303bdae7f..83888c7aa 100644 --- a/infer/tests/codetoanalyze/objc/errors/issues.exp +++ b/infer/tests/codetoanalyze/objc/errors/issues.exp @@ -111,6 +111,7 @@ codetoanalyze/objc/errors/npe/block.m, BlockA_foo7, 2, IVAR_NOT_NULL_CHECKED, [s codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, [start of procedure ivar_npe] codetoanalyze/objc/errors/npe/skip_method_with_nil_object.m, SkipMethodNilA_testBug:, 6, PARAMETER_NOT_NULL_CHECKED, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Condition is false] codetoanalyze/objc/errors/property/main.c, property_main, 3, MEMORY_LEAK, [start of procedure property_main(),Skipped call: function or method not found] +codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m, __objc_anonymous_block_ProcessContentsOfFile______2, 6, MEMORY_LEAK, [start of procedure block,Skipped call: function or method not found,Condition is true,Skipped call: function or method not found] codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie1, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie1()] codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie2, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie2()] codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie3, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie3()] diff --git a/infer/tests/codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m b/infer/tests/codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m new file mode 100644 index 000000000..5659c83a1 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017 - 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. + */ +#import + +Boolean MyProcessFileData(char* buffer, ssize_t actual); + +dispatch_source_t ProcessContentsOfFile(const char* filename) { + // Prepare the file for reading. + int fd = open("hi.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd == -1) + return NULL; + fcntl(fd, F_SETFL, O_NONBLOCK); // Avoid blocking the read operation + + dispatch_queue_t queue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + dispatch_source_t readSource = + dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, queue); + if (!readSource) { + close(fd); + return NULL; + } + + // Install the event handler + dispatch_source_set_event_handler(readSource, ^{ + size_t estimated = dispatch_source_get_data(readSource) + 1; + // Read the data into a text buffer. + char* buffer = (char*)malloc(estimated); + if (buffer) { + ssize_t actual = read(fd, buffer, (estimated)); + Boolean done = MyProcessFileData(buffer, actual); // Process the data. + + // Release the buffer when done. + // free(buffer); // Don't release the buffer, report memory leak. + + // If there is no more data, cancel the source. + if (done) + dispatch_source_cancel(readSource); + } + }); + + // Install the cancellation handler + dispatch_source_set_cancel_handler(readSource, ^{ + close(fd); + }); + + // Start reading the file. + dispatch_resume(readSource); + return readSource; +}