161a76f58SEndre FülöpFAQ and How to Deal with Common False Positives 261a76f58SEndre Fülöp=============================================== 361a76f58SEndre Fülöp 461a76f58SEndre Fülöp.. contents:: 561a76f58SEndre Fülöp :local: 661a76f58SEndre Fülöp 761a76f58SEndre FülöpCustom Assertions 861a76f58SEndre Fülöp----------------- 961a76f58SEndre Fülöp 1061a76f58SEndre FülöpQ: How do I tell the analyzer that I do not want the bug being reported here since my custom error handler will safely end the execution before the bug is reached? 1161a76f58SEndre Fülöp 12*ed80d0c2SDonát Nagy.. image:: ../images/example_custom_assert.png 13*ed80d0c2SDonát Nagy 1421e58ee9SDonát NagyYou can tell the analyzer that this path is unreachable by teaching it about your `custom assertion handlers <Annotations.html#custom-assertion-handlers>`__. For example, you can modify the code segment as following: 1561a76f58SEndre Fülöp 1661a76f58SEndre Fülöp.. code-block:: c 1761a76f58SEndre Fülöp 1861a76f58SEndre Fülöp void customAssert() __attribute__((analyzer_noreturn)); 1961a76f58SEndre Fülöp int foo(int *b) { 2061a76f58SEndre Fülöp if (!b) 2161a76f58SEndre Fülöp customAssert(); 2261a76f58SEndre Fülöp return *b; 2361a76f58SEndre Fülöp } 2461a76f58SEndre Fülöp 2561a76f58SEndre FülöpNull Pointer Dereference 2661a76f58SEndre Fülöp------------------------ 2761a76f58SEndre Fülöp 2861a76f58SEndre FülöpQ: The analyzer reports a null dereference, but I know that the pointer is never null. How can I tell the analyzer that a pointer can never be null? 2961a76f58SEndre Fülöp 30*ed80d0c2SDonát Nagy.. image:: ../images/example_null_pointer.png 31*ed80d0c2SDonát Nagy 3261a76f58SEndre FülöpThe reason the analyzer often thinks that a pointer can be null is because the preceding code checked compared it against null. If you are absolutely sure that it cannot be null, remove the preceding check and, preferably, add an assertion as well. For example: 3361a76f58SEndre Fülöp 3461a76f58SEndre Fülöp.. code-block:: c 3561a76f58SEndre Fülöp 3661a76f58SEndre Fülöp void usePointer(int *b); 3761a76f58SEndre Fülöp int foo(int *b) { 3861a76f58SEndre Fülöp usePointer(b); 3961a76f58SEndre Fülöp return *b; 4061a76f58SEndre Fülöp } 4161a76f58SEndre Fülöp 4261a76f58SEndre FülöpDead Store 4361a76f58SEndre Fülöp---------- 4461a76f58SEndre Fülöp 4561a76f58SEndre FülöpQ: How do I tell the static analyzer that I don't care about a specific dead store? 4661a76f58SEndre Fülöp 4761a76f58SEndre FülöpWhen the analyzer sees that a value stored into a variable is never used, it's going to produce a message similar to this one: 4861a76f58SEndre Fülöp 4961a76f58SEndre Fülöp.. code-block:: none 5061a76f58SEndre Fülöp 5161a76f58SEndre Fülöp Value stored to 'x' is never read 5261a76f58SEndre Fülöp 5361a76f58SEndre FülöpYou can use the ``(void)x;`` idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future. 5461a76f58SEndre Fülöp 5561a76f58SEndre FülöpUnused Instance Variable 5661a76f58SEndre Fülöp------------------------ 5761a76f58SEndre Fülöp 5861a76f58SEndre FülöpQ: How do I tell the static analyzer that I don't care about a specific unused instance variable in Objective-C? 5961a76f58SEndre Fülöp 6061a76f58SEndre FülöpWhen the analyzer sees that a value stored into a variable is never used, it is going to produce a message similar to this one: 6161a76f58SEndre Fülöp 6261a76f58SEndre Fülöp.. code-block:: none 6361a76f58SEndre Fülöp 6461a76f58SEndre Fülöp Instance variable 'commonName' in class 'HappyBird' is never used by the methods in its @implementation 6561a76f58SEndre Fülöp 6661a76f58SEndre FülöpYou can add ``__attribute__((unused))`` to the instance variable declaration to suppress the warning. 6761a76f58SEndre Fülöp 6861a76f58SEndre FülöpUnlocalized String 6961a76f58SEndre Fülöp------------------ 7061a76f58SEndre Fülöp 7161a76f58SEndre FülöpQ: How do I tell the static analyzer that I don't care about a specific unlocalized string? 7261a76f58SEndre Fülöp 7361a76f58SEndre FülöpWhen the analyzer sees that an unlocalized string is passed to a method that will present that string to the user, it is going to produce a message similar to this one: 7461a76f58SEndre Fülöp 7561a76f58SEndre Fülöp.. code-block:: none 7661a76f58SEndre Fülöp 7761a76f58SEndre Fülöp User-facing text should use localized string macro 7861a76f58SEndre Fülöp 7961a76f58SEndre FülöpIf your project deliberately uses unlocalized user-facing strings (for example, in a debugging UI that is never shown to users), you can suppress the analyzer warnings (and document your intent) with a function that just returns its input but is annotated to return a localized string: 8061a76f58SEndre Fülöp 8161a76f58SEndre Fülöp.. code-block:: objc 8261a76f58SEndre Fülöp 8361a76f58SEndre Fülöp __attribute__((annotate("returns_localized_nsstring"))) 8461a76f58SEndre Fülöp static inline NSString *LocalizationNotNeeded(NSString *s) { 8561a76f58SEndre Fülöp return s; 8661a76f58SEndre Fülöp } 8761a76f58SEndre Fülöp 8861a76f58SEndre FülöpYou can then call this function when creating your debugging UI: 8961a76f58SEndre Fülöp 9061a76f58SEndre Fülöp.. code-block:: objc 9161a76f58SEndre Fülöp 9261a76f58SEndre Fülöp [field setStringValue:LocalizationNotNeeded(@"Debug")]; 9361a76f58SEndre Fülöp 9461a76f58SEndre FülöpSome projects may also find it useful to use NSLocalizedString but add "DNL" or "Do Not Localize" to the string contents as a convention: 9561a76f58SEndre Fülöp 9661a76f58SEndre Fülöp.. code-block:: objc 9761a76f58SEndre Fülöp 9861a76f58SEndre Fülöp UILabel *testLabel = [[UILabel alloc] init]; 9961a76f58SEndre Fülöp NSString *s = NSLocalizedString(@"Hello <Do Not Localize>", @"For debug purposes"); 10061a76f58SEndre Fülöp [testLabel setText:s]; 10161a76f58SEndre Fülöp 10261a76f58SEndre FülöpDealloc in Manual Retain/Release 10361a76f58SEndre Fülöp-------------------------------- 10461a76f58SEndre Fülöp 10561a76f58SEndre FülöpQ: How do I tell the analyzer that my instance variable does not need to be released in -dealloc under Manual Retain/Release? 10661a76f58SEndre Fülöp 10761a76f58SEndre FülöpIf your class only uses an instance variable for part of its lifetime, it may maintain an invariant guaranteeing that the instance variable is always released before -dealloc. In this case, you can silence a warning about a missing release by either adding ``assert(_ivar == nil)`` or an explicit release ``[_ivar release]`` (which will be a no-op when the variable is nil) in -dealloc. 10861a76f58SEndre Fülöp 10961a76f58SEndre FülöpDeciding Nullability 11061a76f58SEndre Fülöp-------------------- 11161a76f58SEndre Fülöp 11261a76f58SEndre FülöpQ: How do I decide whether a method's return type should be _Nullable or _Nonnull? 11361a76f58SEndre Fülöp 11461a76f58SEndre FülöpDepending on the implementation of the method, this puts you in one of five situations: 11561a76f58SEndre Fülöp 11661a76f58SEndre Fülöp1. You actually never return nil. 11761a76f58SEndre Fülöp2. You do return nil sometimes, and callers are supposed to handle that. This includes cases where your method is documented to return nil given certain inputs. 11861a76f58SEndre Fülöp3. You return nil based on some external condition (such as an out-of-memory error), but the client can't do anything about it either. 11961a76f58SEndre Fülöp4. You return nil only when the caller passes input documented to be invalid. That means it's the client's fault. 12061a76f58SEndre Fülöp5. You return nil in some totally undocumented case. 12161a76f58SEndre Fülöp 12261a76f58SEndre FülöpIn (1) you should annotate the method as returning a ``_Nonnull`` object. 12361a76f58SEndre Fülöp 12461a76f58SEndre FülöpIn (2) the method should be marked ``_Nullable``. 12561a76f58SEndre Fülöp 12661a76f58SEndre FülöpIn (3) you should probably annotate the method ``_Nonnull``. Why? Because no callers will actually check for nil, given that they can't do anything about the situation and don't know what went wrong. At this point things have gone so poorly that there's basically no way to recover. 12761a76f58SEndre Fülöp 12861a76f58SEndre FülöpThe least happy case is (4) because the resulting program will almost certainly either crash or just silently do the wrong thing. If this is a new method or you control the callers, you can use ``NSParameterAssert()`` (or the equivalent) to check the precondition and remove the nil return. But if you don't control the callers and they rely on this behavior, you should return mark the method ``_Nonnull`` and return nil cast to _Nonnull anyway. 12961a76f58SEndre Fülöp 13061a76f58SEndre FülöpIf you're in (5), document it, then figure out if you're now in (2), (3), or (4). 13161a76f58SEndre Fülöp 13261a76f58SEndre FülöpIntentional Nullability Violation 13361a76f58SEndre Fülöp--------------------------------- 13461a76f58SEndre Fülöp 13561a76f58SEndre FülöpQ: How do I tell the analyzer that I am intentionally violating nullability? 13661a76f58SEndre Fülöp 13761a76f58SEndre FülöpIn some cases, it may make sense for methods to intentionally violate nullability. For example, your method may — for reasons of backward compatibility — chose to return nil and log an error message in a method with a non-null return type when the client violated a documented precondition rather than check the precondition with ``NSAssert()``. In these cases, you can suppress the analyzer warning with a cast: 13861a76f58SEndre Fülöp 13961a76f58SEndre Fülöp.. code-block:: objc 14061a76f58SEndre Fülöp 14161a76f58SEndre Fülöp return (id _Nonnull)nil; 14261a76f58SEndre Fülöp 14361a76f58SEndre FülöpNote that this cast does not affect code generation. 14461a76f58SEndre Fülöp 14561a76f58SEndre FülöpEnsuring Loop Body Execution 14661a76f58SEndre Fülöp---------------------------- 14761a76f58SEndre Fülöp 14861a76f58SEndre FülöpQ: The analyzer assumes that a loop body is never entered. How can I tell it that the loop body will be entered at least once? 14961a76f58SEndre Fülöp 150*ed80d0c2SDonát Nagy.. image:: ../images/example_use_assert.png 151*ed80d0c2SDonát Nagy 15261a76f58SEndre FülöpIn cases where you know that a loop will always be entered at least once, you can use assertions to inform the analyzer. For example: 15361a76f58SEndre Fülöp 15461a76f58SEndre Fülöp.. code-block:: c 15561a76f58SEndre Fülöp 15661a76f58SEndre Fülöp int foo(int length) { 15761a76f58SEndre Fülöp int x = 0; 15861a76f58SEndre Fülöp assert(length > 0); 15961a76f58SEndre Fülöp for (int i = 0; i < length; i++) 16061a76f58SEndre Fülöp x += 1; 16161a76f58SEndre Fülöp return length/x; 16261a76f58SEndre Fülöp } 16361a76f58SEndre Fülöp 16461a76f58SEndre FülöpBy adding ``assert(length > 0)`` in the beginning of the function, you tell the analyzer that your code is never expecting a zero or a negative value, so it won't need to test the correctness of those paths. 16561a76f58SEndre Fülöp 16661a76f58SEndre FülöpSuppressing Specific Warnings 16761a76f58SEndre Fülöp----------------------------- 16861a76f58SEndre Fülöp 16961a76f58SEndre FülöpQ: How can I suppress a specific analyzer warning? 17061a76f58SEndre Fülöp 17121e58ee9SDonát NagyWhen you encounter an analyzer bug/false positive, check if it's one of the issues discussed above or if the analyzer `annotations <Annotations.html#custom-assertion-handlers>`__ can resolve the issue by helping the static analyzer understand the code better. Second, please `report it <FilingBugs.html>`_ to help us improve user experience. 17261a76f58SEndre Fülöp 17361a76f58SEndre FülöpSometimes there's really no "good" way to eliminate the issue. In such cases you can "silence" it directly by annotating the problematic line of code with the help of Clang attribute 'suppress': 17461a76f58SEndre Fülöp 17561a76f58SEndre Fülöp.. code-block:: c 17661a76f58SEndre Fülöp 17761a76f58SEndre Fülöp int foo() { 17861a76f58SEndre Fülöp int *x = nullptr; 17961a76f58SEndre Fülöp ... 18061a76f58SEndre Fülöp [[clang::suppress]] { 18161a76f58SEndre Fülöp // all warnings in this scope are suppressed 18261a76f58SEndre Fülöp int y = *x; 18361a76f58SEndre Fülöp } 18461a76f58SEndre Fülöp 18561a76f58SEndre Fülöp // null pointer dereference warning suppressed on the next line 18661a76f58SEndre Fülöp [[clang::suppress]] 18761a76f58SEndre Fülöp return *x 18861a76f58SEndre Fülöp } 18961a76f58SEndre Fülöp 19061a76f58SEndre Fülöp int bar(bool coin_flip) { 19161a76f58SEndre Fülöp // suppress all memory leak warnings about this allocation 19261a76f58SEndre Fülöp [[clang::suppress]] 19361a76f58SEndre Fülöp int *result = (int *)malloc(sizeof(int)); 19461a76f58SEndre Fülöp 19561a76f58SEndre Fülöp if (coin_flip) 19661a76f58SEndre Fülöp return 0; // including this leak path 19761a76f58SEndre Fülöp 19861a76f58SEndre Fülöp return *result; // as well as this leak path 19961a76f58SEndre Fülöp } 20061a76f58SEndre Fülöp 20121e58ee9SDonát Nagy.. _exclude_code: 20221e58ee9SDonát Nagy 20361a76f58SEndre FülöpExcluding Code from Analysis 20461a76f58SEndre Fülöp---------------------------- 20561a76f58SEndre Fülöp 20661a76f58SEndre FülöpQ: How can I selectively exclude code the analyzer examines? 20761a76f58SEndre Fülöp 20861a76f58SEndre FülöpWhen the static analyzer is using clang to parse source files, it implicitly defines the preprocessor macro ``__clang_analyzer__``. One can use this macro to selectively exclude code the analyzer examines. Here is an example: 20961a76f58SEndre Fülöp 21061a76f58SEndre Fülöp.. code-block:: c 21161a76f58SEndre Fülöp 21261a76f58SEndre Fülöp #ifndef __clang_analyzer__ 21361a76f58SEndre Fülöp // Code not to be analyzed 21461a76f58SEndre Fülöp #endif 21561a76f58SEndre Fülöp 21661a76f58SEndre FülöpThis usage is discouraged because it makes the code dead to the analyzer from now on. Instead, we prefer that users file bugs against the analyzer when it flags false positives. 217