xref: /llvm-project/clang/docs/analyzer/user-docs/FAQ.rst (revision ed80d0c2ae41888d8d0be90e73026bc126d82161)
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