150
|
1 ==================
|
|
2 Available Checkers
|
|
3 ==================
|
|
4
|
|
5 The analyzer performs checks that are categorized into families or "checkers".
|
|
6
|
|
7 The default set of checkers covers a variety of checks targeted at finding security and API usage bugs,
|
|
8 dead code, and other logic errors. See the :ref:`default-checkers` checkers list below.
|
|
9
|
|
10 In addition to these, the analyzer contains a number of :ref:`alpha-checkers` (aka *alpha* checkers).
|
|
11 These checkers are under development and are switched off by default. They may crash or emit a higher number of false positives.
|
|
12
|
|
13 The :ref:`debug-checkers` package contains checkers for analyzer developers for debugging purposes.
|
|
14
|
|
15 .. contents:: Table of Contents
|
|
16 :depth: 4
|
|
17
|
|
18
|
|
19 .. _default-checkers:
|
|
20
|
|
21 Default Checkers
|
|
22 ----------------
|
|
23
|
|
24 .. _core-checkers:
|
|
25
|
|
26 core
|
|
27 ^^^^
|
|
28 Models core language features and contains general-purpose checkers such as division by zero,
|
|
29 null pointer dereference, usage of uninitialized values, etc.
|
|
30 *These checkers must be always switched on as other checker rely on them.*
|
|
31
|
|
32 .. _core-CallAndMessage:
|
|
33
|
|
34 core.CallAndMessage (C, C++, ObjC)
|
|
35 """"""""""""""""""""""""""""""""""
|
|
36 Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers).
|
|
37
|
|
38 .. literalinclude:: checkers/callandmessage_example.c
|
|
39 :language: objc
|
|
40
|
|
41 .. _core-DivideZero:
|
|
42
|
|
43 core.DivideZero (C, C++, ObjC)
|
|
44 """"""""""""""""""""""""""""""
|
|
45 Check for division by zero.
|
|
46
|
|
47 .. literalinclude:: checkers/dividezero_example.c
|
|
48 :language: c
|
|
49
|
|
50 .. _core-NonNullParamChecker:
|
|
51
|
|
52 core.NonNullParamChecker (C, C++, ObjC)
|
|
53 """""""""""""""""""""""""""""""""""""""
|
|
54 Check for null pointers passed as arguments to a function whose arguments are references or marked with the 'nonnull' attribute.
|
|
55
|
|
56 .. code-block:: cpp
|
|
57
|
|
58 int f(int *p) __attribute__((nonnull));
|
|
59
|
|
60 void test(int *p) {
|
|
61 if (!p)
|
|
62 f(p); // warn
|
|
63 }
|
|
64
|
|
65 .. _core-NullDereference:
|
|
66
|
|
67 core.NullDereference (C, C++, ObjC)
|
|
68 """""""""""""""""""""""""""""""""""
|
|
69 Check for dereferences of null pointers.
|
|
70
|
|
71 .. code-block:: objc
|
|
72
|
|
73 // C
|
|
74 void test(int *p) {
|
|
75 if (p)
|
|
76 return;
|
|
77
|
|
78 int x = p[0]; // warn
|
|
79 }
|
|
80
|
|
81 // C
|
|
82 void test(int *p) {
|
|
83 if (!p)
|
|
84 *p = 0; // warn
|
|
85 }
|
|
86
|
|
87 // C++
|
|
88 class C {
|
|
89 public:
|
|
90 int x;
|
|
91 };
|
|
92
|
|
93 void test() {
|
|
94 C *pc = 0;
|
|
95 int k = pc->x; // warn
|
|
96 }
|
|
97
|
|
98 // Objective-C
|
|
99 @interface MyClass {
|
|
100 @public
|
|
101 int x;
|
|
102 }
|
|
103 @end
|
|
104
|
|
105 void test() {
|
|
106 MyClass *obj = 0;
|
|
107 obj->x = 1; // warn
|
|
108 }
|
|
109
|
|
110 .. _core-StackAddressEscape:
|
|
111
|
|
112 core.StackAddressEscape (C)
|
|
113 """""""""""""""""""""""""""
|
|
114 Check that addresses to stack memory do not escape the function.
|
|
115
|
|
116 .. code-block:: c
|
|
117
|
|
118 char const *p;
|
|
119
|
|
120 void test() {
|
|
121 char const str[] = "string";
|
|
122 p = str; // warn
|
|
123 }
|
|
124
|
|
125 void* test() {
|
|
126 return __builtin_alloca(12); // warn
|
|
127 }
|
|
128
|
|
129 void test() {
|
|
130 static int *x;
|
|
131 int y;
|
|
132 x = &y; // warn
|
|
133 }
|
|
134
|
|
135
|
|
136 .. _core-UndefinedBinaryOperatorResult:
|
|
137
|
|
138 core.UndefinedBinaryOperatorResult (C)
|
|
139 """"""""""""""""""""""""""""""""""""""
|
|
140 Check for undefined results of binary operators.
|
|
141
|
|
142 .. code-block:: c
|
|
143
|
|
144 void test() {
|
|
145 int x;
|
|
146 int y = x + 1; // warn: left operand is garbage
|
|
147 }
|
|
148
|
|
149 .. _core-VLASize:
|
|
150
|
|
151 core.VLASize (C)
|
|
152 """"""""""""""""
|
|
153 Check for declarations of Variable Length Arrays of undefined or zero size.
|
|
154
|
|
155 Check for declarations of VLA of undefined or zero size.
|
|
156
|
|
157 .. code-block:: c
|
|
158
|
|
159 void test() {
|
|
160 int x;
|
|
161 int vla1[x]; // warn: garbage as size
|
|
162 }
|
|
163
|
|
164 void test() {
|
|
165 int x = 0;
|
|
166 int vla2[x]; // warn: zero size
|
|
167 }
|
|
168
|
|
169 .. _core-uninitialized-ArraySubscript:
|
|
170
|
|
171 core.uninitialized.ArraySubscript (C)
|
|
172 """""""""""""""""""""""""""""""""""""
|
|
173 Check for uninitialized values used as array subscripts.
|
|
174
|
|
175 .. code-block:: c
|
|
176
|
|
177 void test() {
|
|
178 int i, a[10];
|
|
179 int x = a[i]; // warn: array subscript is undefined
|
|
180 }
|
|
181
|
|
182 .. _core-uninitialized-Assign:
|
|
183
|
|
184 core.uninitialized.Assign (C)
|
|
185 """""""""""""""""""""""""""""
|
|
186 Check for assigning uninitialized values.
|
|
187
|
|
188 .. code-block:: c
|
|
189
|
|
190 void test() {
|
|
191 int x;
|
|
192 x |= 1; // warn: left expression is uninitialized
|
|
193 }
|
|
194
|
|
195 .. _core-uninitialized-Branch:
|
|
196
|
|
197 core.uninitialized.Branch (C)
|
|
198 """""""""""""""""""""""""""""
|
|
199 Check for uninitialized values used as branch conditions.
|
|
200
|
|
201 .. code-block:: c
|
|
202
|
|
203 void test() {
|
|
204 int x;
|
|
205 if (x) // warn
|
|
206 return;
|
|
207 }
|
|
208
|
|
209 .. _core-uninitialized-CapturedBlockVariable:
|
|
210
|
|
211 core.uninitialized.CapturedBlockVariable (C)
|
|
212 """"""""""""""""""""""""""""""""""""""""""""
|
|
213 Check for blocks that capture uninitialized values.
|
|
214
|
|
215 .. code-block:: c
|
|
216
|
|
217 void test() {
|
|
218 int x;
|
|
219 ^{ int y = x; }(); // warn
|
|
220 }
|
|
221
|
|
222 .. _core-uninitialized-UndefReturn:
|
|
223
|
|
224 core.uninitialized.UndefReturn (C)
|
|
225 """"""""""""""""""""""""""""""""""
|
|
226 Check for uninitialized values being returned to the caller.
|
|
227
|
|
228 .. code-block:: c
|
|
229
|
|
230 int test() {
|
|
231 int x;
|
|
232 return x; // warn
|
|
233 }
|
|
234
|
|
235 .. _cplusplus-checkers:
|
|
236
|
|
237
|
|
238 cplusplus
|
|
239 ^^^^^^^^^
|
|
240
|
|
241 C++ Checkers.
|
|
242
|
|
243 .. _cplusplus-InnerPointer:
|
|
244
|
|
245 cplusplus.InnerPointer (C++)
|
|
246 """"""""""""""""""""""""""""
|
|
247 Check for inner pointers of C++ containers used after re/deallocation.
|
|
248
|
|
249 Many container methods in the C++ standard library are known to invalidate
|
|
250 "references" (including actual references, iterators and raw pointers) to
|
|
251 elements of the container. Using such references after they are invalidated
|
|
252 causes undefined behavior, which is a common source of memory errors in C++ that
|
|
253 this checker is capable of finding.
|
|
254
|
|
255 The checker is currently limited to ``std::string`` objects and doesn't
|
|
256 recognize some of the more sophisticated approaches to passing unowned pointers
|
|
257 around, such as ``std::string_view``.
|
|
258
|
|
259 .. code-block:: cpp
|
|
260
|
|
261 void deref_after_assignment() {
|
|
262 std::string s = "llvm";
|
|
263 const char *c = s.data(); // note: pointer to inner buffer of 'std::string' obtained here
|
|
264 s = "clang"; // note: inner buffer of 'std::string' reallocated by call to 'operator='
|
|
265 consume(c); // warn: inner pointer of container used after re/deallocation
|
|
266 }
|
|
267
|
|
268 const char *return_temp(int x) {
|
|
269 return std::to_string(x).c_str(); // warn: inner pointer of container used after re/deallocation
|
|
270 // note: pointer to inner buffer of 'std::string' obtained here
|
|
271 // note: inner buffer of 'std::string' deallocated by call to destructor
|
|
272 }
|
|
273
|
|
274 .. _cplusplus-NewDelete:
|
|
275
|
|
276 cplusplus.NewDelete (C++)
|
|
277 """""""""""""""""""""""""
|
|
278 Check for double-free and use-after-free problems. Traces memory managed by new/delete.
|
|
279
|
|
280 .. literalinclude:: checkers/newdelete_example.cpp
|
|
281 :language: cpp
|
|
282
|
|
283 .. _cplusplus-NewDeleteLeaks:
|
|
284
|
|
285 cplusplus.NewDeleteLeaks (C++)
|
|
286 """"""""""""""""""""""""""""""
|
|
287 Check for memory leaks. Traces memory managed by new/delete.
|
|
288
|
|
289 .. code-block:: cpp
|
|
290
|
|
291 void test() {
|
|
292 int *p = new int;
|
|
293 } // warn
|
|
294
|
|
295 .. _cplusplus-PlacementNewChecker:
|
|
296
|
|
297 cplusplus.PlacementNewChecker (C++)
|
|
298 """""""""""""""""""""""""""""""""""
|
|
299 Check if default placement new is provided with pointers to sufficient storage capacity.
|
|
300
|
|
301 .. code-block:: cpp
|
|
302
|
|
303 #include <new>
|
|
304
|
|
305 void f() {
|
|
306 short s;
|
|
307 long *lp = ::new (&s) long; // warn
|
|
308 }
|
|
309
|
|
310 .. _cplusplus-SelfAssignment:
|
|
311
|
|
312 cplusplus.SelfAssignment (C++)
|
|
313 """"""""""""""""""""""""""""""
|
|
314 Checks C++ copy and move assignment operators for self assignment.
|
|
315
|
|
316 .. _deadcode-checkers:
|
|
317
|
|
318 deadcode
|
|
319 ^^^^^^^^
|
|
320
|
|
321 Dead Code Checkers.
|
|
322
|
|
323 .. _deadcode-DeadStores:
|
|
324
|
|
325 deadcode.DeadStores (C)
|
|
326 """""""""""""""""""""""
|
|
327 Check for values stored to variables that are never read afterwards.
|
|
328
|
|
329 .. code-block:: c
|
|
330
|
|
331 void test() {
|
|
332 int x;
|
|
333 x = 1; // warn
|
|
334 }
|
|
335
|
|
336 The ``WarnForDeadNestedAssignments`` option enables the checker to emit
|
|
337 warnings for nested dead assignments. You can disable with the
|
|
338 ``-analyzer-config deadcode.DeadStores:WarnForDeadNestedAssignments=false``.
|
|
339 *Defaults to true*.
|
|
340
|
|
341 Would warn for this e.g.:
|
|
342 if ((y = make_int())) {
|
|
343 }
|
|
344
|
|
345 .. _nullability-checkers:
|
|
346
|
|
347 nullability
|
|
348 ^^^^^^^^^^^
|
|
349
|
|
350 Objective C checkers that warn for null pointer passing and dereferencing errors.
|
|
351
|
|
352 .. _nullability-NullPassedToNonnull:
|
|
353
|
|
354 nullability.NullPassedToNonnull (ObjC)
|
|
355 """"""""""""""""""""""""""""""""""""""
|
|
356 Warns when a null pointer is passed to a pointer which has a _Nonnull type.
|
|
357
|
|
358 .. code-block:: objc
|
|
359
|
|
360 if (name != nil)
|
|
361 return;
|
|
362 // Warning: nil passed to a callee that requires a non-null 1st parameter
|
|
363 NSString *greeting = [@"Hello " stringByAppendingString:name];
|
|
364
|
|
365 .. _nullability-NullReturnedFromNonnull:
|
|
366
|
|
367 nullability.NullReturnedFromNonnull (ObjC)
|
|
368 """"""""""""""""""""""""""""""""""""""""""
|
|
369 Warns when a null pointer is returned from a function that has _Nonnull return type.
|
|
370
|
|
371 .. code-block:: objc
|
|
372
|
|
373 - (nonnull id)firstChild {
|
|
374 id result = nil;
|
|
375 if ([_children count] > 0)
|
|
376 result = _children[0];
|
|
377
|
|
378 // Warning: nil returned from a method that is expected
|
|
379 // to return a non-null value
|
|
380 return result;
|
|
381 }
|
|
382
|
|
383 .. _nullability-NullableDereferenced:
|
|
384
|
|
385 nullability.NullableDereferenced (ObjC)
|
|
386 """""""""""""""""""""""""""""""""""""""
|
|
387 Warns when a nullable pointer is dereferenced.
|
|
388
|
|
389 .. code-block:: objc
|
|
390
|
|
391 struct LinkedList {
|
|
392 int data;
|
|
393 struct LinkedList *next;
|
|
394 };
|
|
395
|
|
396 struct LinkedList * _Nullable getNext(struct LinkedList *l);
|
|
397
|
|
398 void updateNextData(struct LinkedList *list, int newData) {
|
|
399 struct LinkedList *next = getNext(list);
|
|
400 // Warning: Nullable pointer is dereferenced
|
|
401 next->data = 7;
|
|
402 }
|
|
403
|
|
404 .. _nullability-NullablePassedToNonnull:
|
|
405
|
|
406 nullability.NullablePassedToNonnull (ObjC)
|
|
407 """"""""""""""""""""""""""""""""""""""""""
|
|
408 Warns when a nullable pointer is passed to a pointer which has a _Nonnull type.
|
|
409
|
|
410 .. code-block:: objc
|
|
411
|
|
412 typedef struct Dummy { int val; } Dummy;
|
|
413 Dummy *_Nullable returnsNullable();
|
|
414 void takesNonnull(Dummy *_Nonnull);
|
|
415
|
|
416 void test() {
|
|
417 Dummy *p = returnsNullable();
|
|
418 takesNonnull(p); // warn
|
|
419 }
|
|
420
|
|
421 .. _nullability-NullableReturnedFromNonnull:
|
|
422
|
|
423 nullability.NullableReturnedFromNonnull (ObjC)
|
|
424 """"""""""""""""""""""""""""""""""""""""""""""
|
|
425 Warns when a nullable pointer is returned from a function that has _Nonnull return type.
|
|
426
|
|
427 .. _optin-checkers:
|
|
428
|
|
429 optin
|
|
430 ^^^^^
|
|
431
|
|
432 Checkers for portability, performance or coding style specific rules.
|
|
433
|
|
434 .. _optin-cplusplus-UninitializedObject:
|
|
435
|
|
436 optin.cplusplus.UninitializedObject (C++)
|
|
437 """""""""""""""""""""""""""""""""""""""""
|
|
438
|
|
439 This checker reports uninitialized fields in objects created after a constructor
|
|
440 call. It doesn't only find direct uninitialized fields, but rather makes a deep
|
|
441 inspection of the object, analyzing all of it's fields subfields.
|
|
442 The checker regards inherited fields as direct fields, so one will receive
|
|
443 warnings for uninitialized inherited data members as well.
|
|
444
|
|
445 .. code-block:: cpp
|
|
446
|
|
447 // With Pedantic and CheckPointeeInitialization set to true
|
|
448
|
|
449 struct A {
|
|
450 struct B {
|
|
451 int x; // note: uninitialized field 'this->b.x'
|
|
452 // note: uninitialized field 'this->bptr->x'
|
|
453 int y; // note: uninitialized field 'this->b.y'
|
|
454 // note: uninitialized field 'this->bptr->y'
|
|
455 };
|
|
456 int *iptr; // note: uninitialized pointer 'this->iptr'
|
|
457 B b;
|
|
458 B *bptr;
|
|
459 char *cptr; // note: uninitialized pointee 'this->cptr'
|
|
460
|
|
461 A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
|
|
462 };
|
|
463
|
|
464 void f() {
|
|
465 A::B b;
|
|
466 char c;
|
|
467 A a(&b, &c); // warning: 6 uninitialized fields
|
|
468 // after the constructor call
|
|
469 }
|
|
470
|
|
471 // With Pedantic set to false and
|
|
472 // CheckPointeeInitialization set to true
|
|
473 // (every field is uninitialized)
|
|
474
|
|
475 struct A {
|
|
476 struct B {
|
|
477 int x;
|
|
478 int y;
|
|
479 };
|
|
480 int *iptr;
|
|
481 B b;
|
|
482 B *bptr;
|
|
483 char *cptr;
|
|
484
|
|
485 A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
|
|
486 };
|
|
487
|
|
488 void f() {
|
|
489 A::B b;
|
|
490 char c;
|
|
491 A a(&b, &c); // no warning
|
|
492 }
|
|
493
|
|
494 // With Pedantic set to true and
|
|
495 // CheckPointeeInitialization set to false
|
|
496 // (pointees are regarded as initialized)
|
|
497
|
|
498 struct A {
|
|
499 struct B {
|
|
500 int x; // note: uninitialized field 'this->b.x'
|
|
501 int y; // note: uninitialized field 'this->b.y'
|
|
502 };
|
|
503 int *iptr; // note: uninitialized pointer 'this->iptr'
|
|
504 B b;
|
|
505 B *bptr;
|
|
506 char *cptr;
|
|
507
|
|
508 A (B *bptr, char *cptr) : bptr(bptr), cptr(cptr) {}
|
|
509 };
|
|
510
|
|
511 void f() {
|
|
512 A::B b;
|
|
513 char c;
|
|
514 A a(&b, &c); // warning: 3 uninitialized fields
|
|
515 // after the constructor call
|
|
516 }
|
|
517
|
|
518
|
|
519 **Options**
|
|
520
|
|
521 This checker has several options which can be set from command line (e.g.
|
|
522 ``-analyzer-config optin.cplusplus.UninitializedObject:Pedantic=true``):
|
|
523
|
|
524 * ``Pedantic`` (boolean). If to false, the checker won't emit warnings for
|
|
525 objects that don't have at least one initialized field. Defaults to false.
|
|
526
|
|
527 * ``NotesAsWarnings`` (boolean). If set to true, the checker will emit a
|
|
528 warning for each uninitialized field, as opposed to emitting one warning per
|
|
529 constructor call, and listing the uninitialized fields that belongs to it in
|
|
530 notes. *Defaults to false*.
|
|
531
|
|
532 * ``CheckPointeeInitialization`` (boolean). If set to false, the checker will
|
|
533 not analyze the pointee of pointer/reference fields, and will only check
|
|
534 whether the object itself is initialized. *Defaults to false*.
|
|
535
|
|
536 * ``IgnoreRecordsWithField`` (string). If supplied, the checker will not analyze
|
|
537 structures that have a field with a name or type name that matches the given
|
|
538 pattern. *Defaults to ""*.
|
|
539
|
|
540 .. _optin-cplusplus-VirtualCall:
|
|
541
|
|
542 optin.cplusplus.VirtualCall (C++)
|
|
543 """""""""""""""""""""""""""""""""
|
|
544 Check virtual function calls during construction or destruction.
|
|
545
|
|
546 .. code-block:: cpp
|
|
547
|
|
548 class A {
|
|
549 public:
|
|
550 A() {
|
|
551 f(); // warn
|
|
552 }
|
|
553 virtual void f();
|
|
554 };
|
|
555
|
|
556 class A {
|
|
557 public:
|
|
558 ~A() {
|
|
559 this->f(); // warn
|
|
560 }
|
|
561 virtual void f();
|
|
562 };
|
|
563
|
|
564 .. _optin-mpi-MPI-Checker:
|
|
565
|
|
566 optin.mpi.MPI-Checker (C)
|
|
567 """""""""""""""""""""""""
|
|
568 Checks MPI code.
|
|
569
|
|
570 .. code-block:: c
|
|
571
|
|
572 void test() {
|
|
573 double buf = 0;
|
|
574 MPI_Request sendReq1;
|
|
575 MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM,
|
|
576 0, MPI_COMM_WORLD, &sendReq1);
|
|
577 } // warn: request 'sendReq1' has no matching wait.
|
|
578
|
|
579 void test() {
|
|
580 double buf = 0;
|
|
581 MPI_Request sendReq;
|
|
582 MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq);
|
|
583 MPI_Irecv(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
|
|
584 MPI_Isend(&buf, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &sendReq); // warn
|
|
585 MPI_Wait(&sendReq, MPI_STATUS_IGNORE);
|
|
586 }
|
|
587
|
|
588 void missingNonBlocking() {
|
|
589 int rank = 0;
|
|
590 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
|
591 MPI_Request sendReq1[10][10][10];
|
|
592 MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // warn
|
|
593 }
|
|
594
|
|
595 .. _optin-osx-cocoa-localizability-EmptyLocalizationContextChecker:
|
|
596
|
|
597 optin.osx.cocoa.localizability.EmptyLocalizationContextChecker (ObjC)
|
|
598 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
599 Check that NSLocalizedString macros include a comment for context.
|
|
600
|
|
601 .. code-block:: objc
|
|
602
|
|
603 - (void)test {
|
|
604 NSString *string = NSLocalizedString(@"LocalizedString", nil); // warn
|
|
605 NSString *string2 = NSLocalizedString(@"LocalizedString", @" "); // warn
|
|
606 NSString *string3 = NSLocalizedStringWithDefaultValue(
|
|
607 @"LocalizedString", nil, [[NSBundle alloc] init], nil,@""); // warn
|
|
608 }
|
|
609
|
|
610 .. _optin-osx-cocoa-localizability-NonLocalizedStringChecker:
|
|
611
|
|
612 optin.osx.cocoa.localizability.NonLocalizedStringChecker (ObjC)
|
|
613 """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
614 Warns about uses of non-localized NSStrings passed to UI methods expecting localized NSStrings.
|
|
615
|
|
616 .. code-block:: objc
|
|
617
|
|
618 NSString *alarmText =
|
|
619 NSLocalizedString(@"Enabled", @"Indicates alarm is turned on");
|
|
620 if (!isEnabled) {
|
|
621 alarmText = @"Disabled";
|
|
622 }
|
|
623 UILabel *alarmStateLabel = [[UILabel alloc] init];
|
|
624
|
|
625 // Warning: User-facing text should use localized string macro
|
|
626 [alarmStateLabel setText:alarmText];
|
|
627
|
|
628 .. _optin-performance-GCDAntipattern:
|
|
629
|
|
630 optin.performance.GCDAntipattern
|
|
631 """"""""""""""""""""""""""""""""
|
|
632 Check for performance anti-patterns when using Grand Central Dispatch.
|
|
633
|
|
634 .. _optin-performance-Padding:
|
|
635
|
|
636 optin.performance.Padding
|
|
637 """""""""""""""""""""""""
|
|
638 Check for excessively padded structs.
|
|
639
|
|
640 .. _optin-portability-UnixAPI:
|
|
641
|
|
642 optin.portability.UnixAPI
|
|
643 """""""""""""""""""""""""
|
|
644 Finds implementation-defined behavior in UNIX/Posix functions.
|
|
645
|
|
646
|
|
647 .. _security-checkers:
|
|
648
|
|
649 security
|
|
650 ^^^^^^^^
|
|
651
|
|
652 Security related checkers.
|
|
653
|
|
654 .. _security-FloatLoopCounter:
|
|
655
|
|
656 security.FloatLoopCounter (C)
|
|
657 """""""""""""""""""""""""""""
|
|
658 Warn on using a floating point value as a loop counter (CERT: FLP30-C, FLP30-CPP).
|
|
659
|
|
660 .. code-block:: c
|
|
661
|
|
662 void test() {
|
|
663 for (float x = 0.1f; x <= 1.0f; x += 0.1f) {} // warn
|
|
664 }
|
|
665
|
|
666 .. _security-insecureAPI-UncheckedReturn:
|
|
667
|
|
668 security.insecureAPI.UncheckedReturn (C)
|
|
669 """"""""""""""""""""""""""""""""""""""""
|
|
670 Warn on uses of functions whose return values must be always checked.
|
|
671
|
|
672 .. code-block:: c
|
|
673
|
|
674 void test() {
|
|
675 setuid(1); // warn
|
|
676 }
|
|
677
|
|
678 .. _security-insecureAPI-bcmp:
|
|
679
|
|
680 security.insecureAPI.bcmp (C)
|
|
681 """""""""""""""""""""""""""""
|
|
682 Warn on uses of the 'bcmp' function.
|
|
683
|
|
684 .. code-block:: c
|
|
685
|
|
686 void test() {
|
|
687 bcmp(ptr0, ptr1, n); // warn
|
|
688 }
|
|
689
|
|
690 .. _security-insecureAPI-bcopy:
|
|
691
|
|
692 security.insecureAPI.bcopy (C)
|
|
693 """"""""""""""""""""""""""""""
|
|
694 Warn on uses of the 'bcopy' function.
|
|
695
|
|
696 .. code-block:: c
|
|
697
|
|
698 void test() {
|
|
699 bcopy(src, dst, n); // warn
|
|
700 }
|
|
701
|
|
702 .. _security-insecureAPI-bzero:
|
|
703
|
|
704 security.insecureAPI.bzero (C)
|
|
705 """"""""""""""""""""""""""""""
|
|
706 Warn on uses of the 'bzero' function.
|
|
707
|
|
708 .. code-block:: c
|
|
709
|
|
710 void test() {
|
|
711 bzero(ptr, n); // warn
|
|
712 }
|
|
713
|
|
714 .. _security-insecureAPI-getpw:
|
|
715
|
|
716 security.insecureAPI.getpw (C)
|
|
717 """"""""""""""""""""""""""""""
|
|
718 Warn on uses of the 'getpw' function.
|
|
719
|
|
720 .. code-block:: c
|
|
721
|
|
722 void test() {
|
|
723 char buff[1024];
|
|
724 getpw(2, buff); // warn
|
|
725 }
|
|
726
|
|
727 .. _security-insecureAPI-gets:
|
|
728
|
|
729 security.insecureAPI.gets (C)
|
|
730 """""""""""""""""""""""""""""
|
|
731 Warn on uses of the 'gets' function.
|
|
732
|
|
733 .. code-block:: c
|
|
734
|
|
735 void test() {
|
|
736 char buff[1024];
|
|
737 gets(buff); // warn
|
|
738 }
|
|
739
|
|
740 .. _security-insecureAPI-mkstemp:
|
|
741
|
|
742 security.insecureAPI.mkstemp (C)
|
|
743 """"""""""""""""""""""""""""""""
|
|
744 Warn when 'mkstemp' is passed fewer than 6 X's in the format string.
|
|
745
|
|
746 .. code-block:: c
|
|
747
|
|
748 void test() {
|
|
749 mkstemp("XX"); // warn
|
|
750 }
|
|
751
|
|
752 .. _security-insecureAPI-mktemp:
|
|
753
|
|
754 security.insecureAPI.mktemp (C)
|
|
755 """""""""""""""""""""""""""""""
|
|
756 Warn on uses of the ``mktemp`` function.
|
|
757
|
|
758 .. code-block:: c
|
|
759
|
|
760 void test() {
|
|
761 char *x = mktemp("/tmp/zxcv"); // warn: insecure, use mkstemp
|
|
762 }
|
|
763
|
|
764 .. _security-insecureAPI-rand:
|
|
765
|
|
766 security.insecureAPI.rand (C)
|
|
767 """""""""""""""""""""""""""""
|
|
768 Warn on uses of inferior random number generating functions (only if arc4random function is available):
|
|
769 ``drand48, erand48, jrand48, lcong48, lrand48, mrand48, nrand48, random, rand_r``.
|
|
770
|
|
771 .. code-block:: c
|
|
772
|
|
773 void test() {
|
|
774 random(); // warn
|
|
775 }
|
|
776
|
|
777 .. _security-insecureAPI-strcpy:
|
|
778
|
|
779 security.insecureAPI.strcpy (C)
|
|
780 """""""""""""""""""""""""""""""
|
|
781 Warn on uses of the ``strcpy`` and ``strcat`` functions.
|
|
782
|
|
783 .. code-block:: c
|
|
784
|
|
785 void test() {
|
|
786 char x[4];
|
|
787 char *y = "abcd";
|
|
788
|
|
789 strcpy(x, y); // warn
|
|
790 }
|
|
791
|
|
792
|
|
793 .. _security-insecureAPI-vfork:
|
|
794
|
|
795 security.insecureAPI.vfork (C)
|
|
796 """"""""""""""""""""""""""""""
|
|
797 Warn on uses of the 'vfork' function.
|
|
798
|
|
799 .. code-block:: c
|
|
800
|
|
801 void test() {
|
|
802 vfork(); // warn
|
|
803 }
|
|
804
|
|
805 .. _security-insecureAPI-DeprecatedOrUnsafeBufferHandling:
|
|
806
|
|
807 security.insecureAPI.DeprecatedOrUnsafeBufferHandling (C)
|
|
808 """""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
809 Warn on occurrences of unsafe or deprecated buffer handling functions, which now have a secure variant: ``sprintf, vsprintf, scanf, wscanf, fscanf, fwscanf, vscanf, vwscanf, vfscanf, vfwscanf, sscanf, swscanf, vsscanf, vswscanf, swprintf, snprintf, vswprintf, vsnprintf, memcpy, memmove, strncpy, strncat, memset``
|
|
810
|
|
811 .. code-block:: c
|
|
812
|
|
813 void test() {
|
|
814 char buf [5];
|
|
815 strncpy(buf, "a", 1); // warn
|
|
816 }
|
|
817
|
|
818 .. _unix-checkers:
|
|
819
|
|
820 unix
|
|
821 ^^^^
|
|
822 POSIX/Unix checkers.
|
|
823
|
|
824 .. _unix-API:
|
|
825
|
|
826 unix.API (C)
|
|
827 """"""""""""
|
|
828 Check calls to various UNIX/Posix functions: ``open, pthread_once, calloc, malloc, realloc, alloca``.
|
|
829
|
|
830 .. literalinclude:: checkers/unix_api_example.c
|
|
831 :language: c
|
|
832
|
|
833 .. _unix-Malloc:
|
|
834
|
|
835 unix.Malloc (C)
|
|
836 """""""""""""""
|
|
837 Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().
|
|
838
|
|
839 .. literalinclude:: checkers/unix_malloc_example.c
|
|
840 :language: c
|
|
841
|
|
842 .. _unix-MallocSizeof:
|
|
843
|
|
844 unix.MallocSizeof (C)
|
|
845 """""""""""""""""""""
|
|
846 Check for dubious ``malloc`` arguments involving ``sizeof``.
|
|
847
|
|
848 .. code-block:: c
|
|
849
|
|
850 void test() {
|
|
851 long *p = malloc(sizeof(short));
|
|
852 // warn: result is converted to 'long *', which is
|
|
853 // incompatible with operand type 'short'
|
|
854 free(p);
|
|
855 }
|
|
856
|
|
857 .. _unix-MismatchedDeallocator:
|
|
858
|
|
859 unix.MismatchedDeallocator (C, C++)
|
|
860 """""""""""""""""""""""""""""""""""
|
|
861 Check for mismatched deallocators.
|
|
862
|
|
863 .. literalinclude:: checkers/mismatched_deallocator_example.cpp
|
|
864 :language: c
|
|
865
|
|
866 .. _unix-Vfork:
|
|
867
|
|
868 unix.Vfork (C)
|
|
869 """"""""""""""
|
|
870 Check for proper usage of ``vfork``.
|
|
871
|
|
872 .. code-block:: c
|
|
873
|
|
874 int test(int x) {
|
|
875 pid_t pid = vfork(); // warn
|
|
876 if (pid != 0)
|
|
877 return 0;
|
|
878
|
|
879 switch (x) {
|
|
880 case 0:
|
|
881 pid = 1;
|
|
882 execl("", "", 0);
|
|
883 _exit(1);
|
|
884 break;
|
|
885 case 1:
|
|
886 x = 0; // warn: this assignment is prohibited
|
|
887 break;
|
|
888 case 2:
|
|
889 foo(); // warn: this function call is prohibited
|
|
890 break;
|
|
891 default:
|
|
892 return 0; // warn: return is prohibited
|
|
893 }
|
|
894
|
|
895 while(1);
|
|
896 }
|
|
897
|
|
898 .. _unix-cstring-BadSizeArg:
|
|
899
|
|
900 unix.cstring.BadSizeArg (C)
|
|
901 """""""""""""""""""""""""""
|
|
902 Check the size argument passed into C string functions for common erroneous patterns. Use ``-Wno-strncat-size`` compiler option to mute other ``strncat``-related compiler warnings.
|
|
903
|
|
904 .. code-block:: c
|
|
905
|
|
906 void test() {
|
|
907 char dest[3];
|
|
908 strncat(dest, """""""""""""""""""""""""*", sizeof(dest));
|
|
909 // warn: potential buffer overflow
|
|
910 }
|
|
911
|
|
912 .. _unix-cstrisng-NullArg:
|
|
913
|
|
914 unix.cstrisng.NullArg (C)
|
|
915 """""""""""""""""""""""""
|
|
916 Check for null pointers being passed as arguments to C string functions:
|
|
917 ``strlen, strnlen, strcpy, strncpy, strcat, strncat, strcmp, strncmp, strcasecmp, strncasecmp``.
|
|
918
|
|
919 .. code-block:: c
|
|
920
|
|
921 int test() {
|
|
922 return strlen(0); // warn
|
|
923 }
|
|
924
|
|
925 .. _osx-checkers:
|
|
926
|
|
927 osx
|
|
928 ^^^
|
|
929 macOS checkers.
|
|
930
|
|
931 .. _osx-API:
|
|
932
|
|
933 osx.API (C)
|
|
934 """""""""""
|
|
935 Check for proper uses of various Apple APIs.
|
|
936
|
|
937 .. code-block:: objc
|
|
938
|
|
939 void test() {
|
|
940 dispatch_once_t pred = 0;
|
|
941 dispatch_once(&pred, ^(){}); // warn: dispatch_once uses local
|
|
942 }
|
|
943
|
|
944 .. _osx-NumberObjectConversion:
|
|
945
|
|
946 osx.NumberObjectConversion (C, C++, ObjC)
|
|
947 """""""""""""""""""""""""""""""""""""""""
|
|
948 Check for erroneous conversions of objects representing numbers into numbers.
|
|
949
|
|
950 .. code-block:: objc
|
|
951
|
|
952 NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
|
|
953 // Warning: Comparing a pointer value of type 'NSNumber *'
|
|
954 // to a scalar integer value
|
|
955 if (photoCount > 0) {
|
|
956 [self displayPhotos];
|
|
957 }
|
|
958
|
|
959 .. _osx-ObjCProperty:
|
|
960
|
|
961 osx.ObjCProperty (ObjC)
|
|
962 """""""""""""""""""""""
|
|
963 Check for proper uses of Objective-C properties.
|
|
964
|
|
965 .. code-block:: objc
|
|
966
|
|
967 NSNumber *photoCount = [albumDescriptor objectForKey:@"PhotoCount"];
|
|
968 // Warning: Comparing a pointer value of type 'NSNumber *'
|
|
969 // to a scalar integer value
|
|
970 if (photoCount > 0) {
|
|
971 [self displayPhotos];
|
|
972 }
|
|
973
|
|
974
|
|
975 .. _osx-SecKeychainAPI:
|
|
976
|
|
977 osx.SecKeychainAPI (C)
|
|
978 """"""""""""""""""""""
|
|
979 Check for proper uses of Secure Keychain APIs.
|
|
980
|
|
981 .. literalinclude:: checkers/seckeychainapi_example.m
|
|
982 :language: objc
|
|
983
|
|
984 .. _osx-cocoa-AtSync:
|
|
985
|
|
986 osx.cocoa.AtSync (ObjC)
|
|
987 """""""""""""""""""""""
|
|
988 Check for nil pointers used as mutexes for @synchronized.
|
|
989
|
|
990 .. code-block:: objc
|
|
991
|
|
992 void test(id x) {
|
|
993 if (!x)
|
|
994 @synchronized(x) {} // warn: nil value used as mutex
|
|
995 }
|
|
996
|
|
997 void test() {
|
|
998 id y;
|
|
999 @synchronized(y) {} // warn: uninitialized value used as mutex
|
|
1000 }
|
|
1001
|
|
1002 .. _osx-cocoa-AutoreleaseWrite:
|
|
1003
|
|
1004 osx.cocoa.AutoreleaseWrite
|
|
1005 """"""""""""""""""""""""""
|
|
1006 Warn about potentially crashing writes to autoreleasing objects from different autoreleasing pools in Objective-C.
|
|
1007
|
|
1008 .. _osx-cocoa-ClassRelease:
|
|
1009
|
|
1010 osx.cocoa.ClassRelease (ObjC)
|
|
1011 """""""""""""""""""""""""""""
|
|
1012 Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
|
|
1013
|
|
1014 .. code-block:: objc
|
|
1015
|
|
1016 @interface MyClass : NSObject
|
|
1017 @end
|
|
1018
|
|
1019 void test(void) {
|
|
1020 [MyClass release]; // warn
|
|
1021 }
|
|
1022
|
|
1023 .. _osx-cocoa-Dealloc:
|
|
1024
|
|
1025 osx.cocoa.Dealloc (ObjC)
|
|
1026 """"""""""""""""""""""""
|
|
1027 Warn about Objective-C classes that lack a correct implementation of -dealloc
|
|
1028
|
|
1029 .. literalinclude:: checkers/dealloc_example.m
|
|
1030 :language: objc
|
|
1031
|
|
1032 .. _osx-cocoa-IncompatibleMethodTypes:
|
|
1033
|
|
1034 osx.cocoa.IncompatibleMethodTypes (ObjC)
|
|
1035 """"""""""""""""""""""""""""""""""""""""
|
|
1036 Warn about Objective-C method signatures with type incompatibilities.
|
|
1037
|
|
1038 .. code-block:: objc
|
|
1039
|
|
1040 @interface MyClass1 : NSObject
|
|
1041 - (int)foo;
|
|
1042 @end
|
|
1043
|
|
1044 @implementation MyClass1
|
|
1045 - (int)foo { return 1; }
|
|
1046 @end
|
|
1047
|
|
1048 @interface MyClass2 : MyClass1
|
|
1049 - (float)foo;
|
|
1050 @end
|
|
1051
|
|
1052 @implementation MyClass2
|
|
1053 - (float)foo { return 1.0; } // warn
|
|
1054 @end
|
|
1055
|
|
1056 .. _osx-cocoa-Loops:
|
|
1057
|
|
1058 osx.cocoa.Loops
|
|
1059 """""""""""""""
|
|
1060 Improved modeling of loops using Cocoa collection types.
|
|
1061
|
|
1062 .. _osx-cocoa-MissingSuperCall:
|
|
1063
|
|
1064 osx.cocoa.MissingSuperCall (ObjC)
|
|
1065 """""""""""""""""""""""""""""""""
|
|
1066 Warn about Objective-C methods that lack a necessary call to super.
|
|
1067
|
|
1068 .. code-block:: objc
|
|
1069
|
|
1070 @interface Test : UIViewController
|
|
1071 @end
|
|
1072 @implementation test
|
|
1073 - (void)viewDidLoad {} // warn
|
|
1074 @end
|
|
1075
|
|
1076
|
|
1077 .. _osx-cocoa-NSAutoreleasePool:
|
|
1078
|
|
1079 osx.cocoa.NSAutoreleasePool (ObjC)
|
|
1080 """"""""""""""""""""""""""""""""""
|
|
1081 Warn for suboptimal uses of NSAutoreleasePool in Objective-C GC mode.
|
|
1082
|
|
1083 .. code-block:: objc
|
|
1084
|
|
1085 void test() {
|
|
1086 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
|
1087 [pool release]; // warn
|
|
1088 }
|
|
1089
|
|
1090 .. _osx-cocoa-NSError:
|
|
1091
|
|
1092 osx.cocoa.NSError (ObjC)
|
|
1093 """"""""""""""""""""""""
|
|
1094 Check usage of NSError parameters.
|
|
1095
|
|
1096 .. code-block:: objc
|
|
1097
|
|
1098 @interface A : NSObject
|
|
1099 - (void)foo:(NSError """""""""""""""""""""""")error;
|
|
1100 @end
|
|
1101
|
|
1102 @implementation A
|
|
1103 - (void)foo:(NSError """""""""""""""""""""""")error {
|
|
1104 // warn: method accepting NSError"""""""""""""""""""""""" should have a non-void
|
|
1105 // return value
|
|
1106 }
|
|
1107 @end
|
|
1108
|
|
1109 @interface A : NSObject
|
|
1110 - (BOOL)foo:(NSError """""""""""""""""""""""")error;
|
|
1111 @end
|
|
1112
|
|
1113 @implementation A
|
|
1114 - (BOOL)foo:(NSError """""""""""""""""""""""")error {
|
|
1115 *error = 0; // warn: potential null dereference
|
|
1116 return 0;
|
|
1117 }
|
|
1118 @end
|
|
1119
|
|
1120 .. _osx-cocoa-NilArg:
|
|
1121
|
|
1122 osx.cocoa.NilArg (ObjC)
|
|
1123 """""""""""""""""""""""
|
|
1124 Check for prohibited nil arguments to ObjC method calls.
|
|
1125
|
|
1126 - caseInsensitiveCompare:
|
|
1127 - compare:
|
|
1128 - compare:options:
|
|
1129 - compare:options:range:
|
|
1130 - compare:options:range:locale:
|
|
1131 - componentsSeparatedByCharactersInSet:
|
|
1132 - initWithFormat:
|
|
1133
|
|
1134 .. code-block:: objc
|
|
1135
|
|
1136 NSComparisonResult test(NSString *s) {
|
|
1137 NSString *aString = nil;
|
|
1138 return [s caseInsensitiveCompare:aString];
|
|
1139 // warn: argument to 'NSString' method
|
|
1140 // 'caseInsensitiveCompare:' cannot be nil
|
|
1141 }
|
|
1142
|
|
1143
|
|
1144 .. _osx-cocoa-NonNilReturnValue:
|
|
1145
|
|
1146 osx.cocoa.NonNilReturnValue
|
|
1147 """""""""""""""""""""""""""
|
|
1148 Models the APIs that are guaranteed to return a non-nil value.
|
|
1149
|
|
1150 .. _osx-cocoa-ObjCGenerics:
|
|
1151
|
|
1152 osx.cocoa.ObjCGenerics (ObjC)
|
|
1153 """""""""""""""""""""""""""""
|
|
1154 Check for type errors when using Objective-C generics.
|
|
1155
|
|
1156 .. code-block:: objc
|
|
1157
|
|
1158 NSMutableArray *names = [NSMutableArray array];
|
|
1159 NSMutableArray *birthDates = names;
|
|
1160
|
|
1161 // Warning: Conversion from value of type 'NSDate *'
|
|
1162 // to incompatible type 'NSString *'
|
|
1163 [birthDates addObject: [NSDate date]];
|
|
1164
|
|
1165 .. _osx-cocoa-RetainCount:
|
|
1166
|
|
1167 osx.cocoa.RetainCount (ObjC)
|
|
1168 """"""""""""""""""""""""""""
|
|
1169 Check for leaks and improper reference count management
|
|
1170
|
|
1171 .. code-block:: objc
|
|
1172
|
|
1173 void test() {
|
|
1174 NSString *s = [[NSString alloc] init]; // warn
|
|
1175 }
|
|
1176
|
|
1177 CFStringRef test(char *bytes) {
|
|
1178 return CFStringCreateWithCStringNoCopy(
|
|
1179 0, bytes, NSNEXTSTEPStringEncoding, 0); // warn
|
|
1180 }
|
|
1181
|
|
1182
|
|
1183 .. _osx-cocoa-RunLoopAutoreleaseLeak:
|
|
1184
|
|
1185 osx.cocoa.RunLoopAutoreleaseLeak
|
|
1186 """"""""""""""""""""""""""""""""
|
|
1187 Check for leaked memory in autorelease pools that will never be drained.
|
|
1188
|
|
1189 .. _osx-cocoa-SelfInit:
|
|
1190
|
|
1191 osx.cocoa.SelfInit (ObjC)
|
|
1192 """""""""""""""""""""""""
|
|
1193 Check that 'self' is properly initialized inside an initializer method.
|
|
1194
|
|
1195 .. code-block:: objc
|
|
1196
|
|
1197 @interface MyObj : NSObject {
|
|
1198 id x;
|
|
1199 }
|
|
1200 - (id)init;
|
|
1201 @end
|
|
1202
|
|
1203 @implementation MyObj
|
|
1204 - (id)init {
|
|
1205 [super init];
|
|
1206 x = 0; // warn: instance variable used while 'self' is not
|
|
1207 // initialized
|
|
1208 return 0;
|
|
1209 }
|
|
1210 @end
|
|
1211
|
|
1212 @interface MyObj : NSObject
|
|
1213 - (id)init;
|
|
1214 @end
|
|
1215
|
|
1216 @implementation MyObj
|
|
1217 - (id)init {
|
|
1218 [super init];
|
|
1219 return self; // warn: returning uninitialized 'self'
|
|
1220 }
|
|
1221 @end
|
|
1222
|
|
1223 .. _osx-cocoa-SuperDealloc:
|
|
1224
|
|
1225 osx.cocoa.SuperDealloc (ObjC)
|
|
1226 """""""""""""""""""""""""""""
|
|
1227 Warn about improper use of '[super dealloc]' in Objective-C.
|
|
1228
|
|
1229 .. code-block:: objc
|
|
1230
|
|
1231 @interface SuperDeallocThenReleaseIvarClass : NSObject {
|
|
1232 NSObject *_ivar;
|
|
1233 }
|
|
1234 @end
|
|
1235
|
|
1236 @implementation SuperDeallocThenReleaseIvarClass
|
|
1237 - (void)dealloc {
|
|
1238 [super dealloc];
|
|
1239 [_ivar release]; // warn
|
|
1240 }
|
|
1241 @end
|
|
1242
|
|
1243 .. _osx-cocoa-UnusedIvars:
|
|
1244
|
|
1245 osx.cocoa.UnusedIvars (ObjC)
|
|
1246 """"""""""""""""""""""""""""
|
|
1247 Warn about private ivars that are never used.
|
|
1248
|
|
1249 .. code-block:: objc
|
|
1250
|
|
1251 @interface MyObj : NSObject {
|
|
1252 @private
|
|
1253 id x; // warn
|
|
1254 }
|
|
1255 @end
|
|
1256
|
|
1257 @implementation MyObj
|
|
1258 @end
|
|
1259
|
|
1260 .. _osx-cocoa-VariadicMethodTypes:
|
|
1261
|
|
1262 osx.cocoa.VariadicMethodTypes (ObjC)
|
|
1263 """"""""""""""""""""""""""""""""""""
|
|
1264 Check for passing non-Objective-C types to variadic collection
|
|
1265 initialization methods that expect only Objective-C types.
|
|
1266
|
|
1267 .. code-block:: objc
|
|
1268
|
|
1269 void test() {
|
|
1270 [NSSet setWithObjects:@"Foo", "Bar", nil];
|
|
1271 // warn: argument should be an ObjC pointer type, not 'char *'
|
|
1272 }
|
|
1273
|
|
1274 .. _osx-coreFoundation-CFError:
|
|
1275
|
|
1276 osx.coreFoundation.CFError (C)
|
|
1277 """"""""""""""""""""""""""""""
|
|
1278 Check usage of CFErrorRef* parameters
|
|
1279
|
|
1280 .. code-block:: c
|
|
1281
|
|
1282 void test(CFErrorRef *error) {
|
|
1283 // warn: function accepting CFErrorRef* should have a
|
|
1284 // non-void return
|
|
1285 }
|
|
1286
|
|
1287 int foo(CFErrorRef *error) {
|
|
1288 *error = 0; // warn: potential null dereference
|
|
1289 return 0;
|
|
1290 }
|
|
1291
|
|
1292 .. _osx-coreFoundation-CFNumber:
|
|
1293
|
|
1294 osx.coreFoundation.CFNumber (C)
|
|
1295 """""""""""""""""""""""""""""""
|
|
1296 Check for proper uses of CFNumber APIs.
|
|
1297
|
|
1298 .. code-block:: c
|
|
1299
|
|
1300 CFNumberRef test(unsigned char x) {
|
|
1301 return CFNumberCreate(0, kCFNumberSInt16Type, &x);
|
|
1302 // warn: 8 bit integer is used to initialize a 16 bit integer
|
|
1303 }
|
|
1304
|
|
1305 .. _osx-coreFoundation-CFRetainRelease:
|
|
1306
|
|
1307 osx.coreFoundation.CFRetainRelease (C)
|
|
1308 """"""""""""""""""""""""""""""""""""""
|
|
1309 Check for null arguments to CFRetain/CFRelease/CFMakeCollectable.
|
|
1310
|
|
1311 .. code-block:: c
|
|
1312
|
|
1313 void test(CFTypeRef p) {
|
|
1314 if (!p)
|
|
1315 CFRetain(p); // warn
|
|
1316 }
|
|
1317
|
|
1318 void test(int x, CFTypeRef p) {
|
|
1319 if (p)
|
|
1320 return;
|
|
1321
|
|
1322 CFRelease(p); // warn
|
|
1323 }
|
|
1324
|
|
1325 .. _osx-coreFoundation-containers-OutOfBounds:
|
|
1326
|
|
1327 osx.coreFoundation.containers.OutOfBounds (C)
|
|
1328 """""""""""""""""""""""""""""""""""""""""""""
|
|
1329 Checks for index out-of-bounds when using 'CFArray' API.
|
|
1330
|
|
1331 .. code-block:: c
|
|
1332
|
|
1333 void test() {
|
|
1334 CFArrayRef A = CFArrayCreate(0, 0, 0, &kCFTypeArrayCallBacks);
|
|
1335 CFArrayGetValueAtIndex(A, 0); // warn
|
|
1336 }
|
|
1337
|
|
1338 .. _osx-coreFoundation-containers-PointerSizedValues:
|
|
1339
|
|
1340 osx.coreFoundation.containers.PointerSizedValues (C)
|
|
1341 """"""""""""""""""""""""""""""""""""""""""""""""""""
|
|
1342 Warns if 'CFArray', 'CFDictionary', 'CFSet' are created with non-pointer-size values.
|
|
1343
|
|
1344 .. code-block:: c
|
|
1345
|
|
1346 void test() {
|
|
1347 int x[] = { 1 };
|
|
1348 CFArrayRef A = CFArrayCreate(0, (const void """""""""""""""""""""""")x, 1,
|
|
1349 &kCFTypeArrayCallBacks); // warn
|
|
1350 }
|
|
1351
|
|
1352 Fuchsia
|
|
1353 ^^^^^^^
|
|
1354
|
|
1355 Fuchsia is an open source capability-based operating system currently being
|
|
1356 developed by Google. This section describes checkers that can find various
|
|
1357 misuses of Fuchsia APIs.
|
|
1358
|
|
1359 .. _fuchsia-HandleChecker:
|
|
1360
|
|
1361 fuchsia.HandleChecker
|
|
1362 """"""""""""""""""""""""""""
|
|
1363 Handles identify resources. Similar to pointers they can be leaked,
|
|
1364 double freed, or use after freed. This check attempts to find such problems.
|
|
1365
|
|
1366 .. code-block:: cpp
|
|
1367
|
|
1368 void checkLeak08(int tag) {
|
|
1369 zx_handle_t sa, sb;
|
|
1370 zx_channel_create(0, &sa, &sb);
|
|
1371 if (tag)
|
|
1372 zx_handle_close(sa);
|
|
1373 use(sb); // Warn: Potential leak of handle
|
|
1374 zx_handle_close(sb);
|
|
1375 }
|
|
1376
|
173
|
1377 WebKit
|
|
1378 ^^^^^^
|
|
1379
|
|
1380 WebKit is an open-source web browser engine available for macOS, iOS and Linux.
|
|
1381 This section describes checkers that can find issues in WebKit codebase.
|
|
1382
|
|
1383 Most of the checkers focus on memory management for which WebKit uses custom implementation of reference counted smartpointers.
|
|
1384 Checker are formulated in terms related to ref-counting:
|
|
1385 * *Ref-counted type* is either ``Ref<T>`` or ``RefPtr<T>``.
|
|
1386 * *Ref-countable type* is any type that implements ``ref()`` and ``deref()`` methods as ``RefPtr<>`` is a template (i. e. relies on duck typing).
|
|
1387 * *Uncounted type* is ref-countable but not ref-counted type.
|
|
1388
|
|
1389 .. _webkit-RefCntblBaseVirtualDtor:
|
|
1390
|
|
1391 webkit.RefCntblBaseVirtualDtor
|
|
1392 """"""""""""""""""""""""""""""""""""
|
|
1393 All uncounted types used as base classes must have a virtual destructor.
|
|
1394
|
|
1395 Ref-counted types hold their ref-countable data by a raw pointer and allow implicit upcasting from ref-counted pointer to derived type to ref-counted pointer to base type. This might lead to an object of (dynamic) derived type being deleted via pointer to the base class type which C++ standard defines as UB in case the base class doesn't have virtual destructor ``[expr.delete]``.
|
|
1396
|
|
1397 .. code-block:: cpp
|
|
1398
|
|
1399 struct RefCntblBase {
|
|
1400 void ref() {}
|
|
1401 void deref() {}
|
|
1402 };
|
|
1403
|
|
1404 struct Derived : RefCntblBase { }; // warn
|
150
|
1405
|
|
1406 .. _alpha-checkers:
|
|
1407
|
|
1408 Experimental Checkers
|
|
1409 ---------------------
|
|
1410
|
|
1411 *These are checkers with known issues or limitations that keep them from being on by default. They are likely to have false positives. Bug reports and especially patches are welcome.*
|
|
1412
|
|
1413 alpha.clone
|
|
1414 ^^^^^^^^^^^
|
|
1415
|
|
1416 .. _alpha-clone-CloneChecker:
|
|
1417
|
|
1418 alpha.clone.CloneChecker (C, C++, ObjC)
|
|
1419 """""""""""""""""""""""""""""""""""""""
|
|
1420 Reports similar pieces of code.
|
|
1421
|
|
1422 .. code-block:: c
|
|
1423
|
|
1424 void log();
|
|
1425
|
|
1426 int max(int a, int b) { // warn
|
|
1427 log();
|
|
1428 if (a > b)
|
|
1429 return a;
|
|
1430 return b;
|
|
1431 }
|
|
1432
|
|
1433 int maxClone(int x, int y) { // similar code here
|
|
1434 log();
|
|
1435 if (x > y)
|
|
1436 return x;
|
|
1437 return y;
|
|
1438 }
|
|
1439
|
|
1440 .. _alpha-core-BoolAssignment:
|
|
1441
|
|
1442 alpha.core.BoolAssignment (ObjC)
|
|
1443 """"""""""""""""""""""""""""""""
|
|
1444 Warn about assigning non-{0,1} values to boolean variables.
|
|
1445
|
|
1446 .. code-block:: objc
|
|
1447
|
|
1448 void test() {
|
|
1449 BOOL b = -1; // warn
|
|
1450 }
|
|
1451
|
|
1452 alpha.core
|
|
1453 ^^^^^^^^^^
|
|
1454
|
|
1455 .. _alpha-core-CallAndMessageUnInitRefArg:
|
|
1456
|
|
1457 alpha.core.CallAndMessageUnInitRefArg (C,C++, ObjC)
|
|
1458 """""""""""""""""""""""""""""""""""""""""""""""""""
|
|
1459 Check for logical errors for function calls and Objective-C
|
|
1460 message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables).
|
|
1461
|
|
1462 .. code-block:: c
|
|
1463
|
|
1464 void test(void) {
|
|
1465 int t;
|
|
1466 int &p = t;
|
|
1467 int &s = p;
|
|
1468 int &q = s;
|
|
1469 foo(q); // warn
|
|
1470 }
|
|
1471
|
|
1472 void test(void) {
|
|
1473 int x;
|
|
1474 foo(&x); // warn
|
|
1475 }
|
|
1476
|
|
1477 .. _alpha-core-CastSize:
|
|
1478
|
|
1479 alpha.core.CastSize (C)
|
|
1480 """""""""""""""""""""""
|
|
1481 Check when casting a malloc'ed type ``T``, whether the size is a multiple of the size of ``T``.
|
|
1482
|
|
1483 .. code-block:: c
|
|
1484
|
|
1485 void test() {
|
|
1486 int *x = (int *) malloc(11); // warn
|
|
1487 }
|
|
1488
|
|
1489 .. _alpha-core-CastToStruct:
|
|
1490
|
|
1491 alpha.core.CastToStruct (C, C++)
|
|
1492 """"""""""""""""""""""""""""""""
|
|
1493 Check for cast from non-struct pointer to struct pointer.
|
|
1494
|
|
1495 .. code-block:: cpp
|
|
1496
|
|
1497 // C
|
|
1498 struct s {};
|
|
1499
|
|
1500 void test(int *p) {
|
|
1501 struct s *ps = (struct s *) p; // warn
|
|
1502 }
|
|
1503
|
|
1504 // C++
|
|
1505 class c {};
|
|
1506
|
|
1507 void test(int *p) {
|
|
1508 c *pc = (c *) p; // warn
|
|
1509 }
|
|
1510
|
|
1511 .. _alpha-core-Conversion:
|
|
1512
|
|
1513 alpha.core.Conversion (C, C++, ObjC)
|
|
1514 """"""""""""""""""""""""""""""""""""
|
|
1515 Loss of sign/precision in implicit conversions.
|
|
1516
|
|
1517 .. code-block:: c
|
|
1518
|
|
1519 void test(unsigned U, signed S) {
|
|
1520 if (S > 10) {
|
|
1521 if (U < S) {
|
|
1522 }
|
|
1523 }
|
|
1524 if (S < -10) {
|
|
1525 if (U < S) { // warn (loss of sign)
|
|
1526 }
|
|
1527 }
|
|
1528 }
|
|
1529
|
|
1530 void test() {
|
|
1531 long long A = 1LL << 60;
|
|
1532 short X = A; // warn (loss of precision)
|
|
1533 }
|
|
1534
|
|
1535 .. _alpha-core-DynamicTypeChecker:
|
|
1536
|
|
1537 alpha.core.DynamicTypeChecker (ObjC)
|
|
1538 """"""""""""""""""""""""""""""""""""
|
|
1539 Check for cases where the dynamic and the static type of an object are unrelated.
|
|
1540
|
|
1541
|
|
1542 .. code-block:: objc
|
|
1543
|
|
1544 id date = [NSDate date];
|
|
1545
|
|
1546 // Warning: Object has a dynamic type 'NSDate *' which is
|
|
1547 // incompatible with static type 'NSNumber *'"
|
|
1548 NSNumber *number = date;
|
|
1549 [number doubleValue];
|
|
1550
|
|
1551 .. _alpha-core-FixedAddr:
|
|
1552
|
|
1553 alpha.core.FixedAddr (C)
|
|
1554 """"""""""""""""""""""""
|
|
1555 Check for assignment of a fixed address to a pointer.
|
|
1556
|
|
1557 .. code-block:: c
|
|
1558
|
|
1559 void test() {
|
|
1560 int *p;
|
|
1561 p = (int *) 0x10000; // warn
|
|
1562 }
|
|
1563
|
|
1564 .. _alpha-core-IdenticalExpr:
|
|
1565
|
|
1566 alpha.core.IdenticalExpr (C, C++)
|
|
1567 """""""""""""""""""""""""""""""""
|
|
1568 Warn about unintended use of identical expressions in operators.
|
|
1569
|
|
1570 .. code-block:: cpp
|
|
1571
|
|
1572 // C
|
|
1573 void test() {
|
|
1574 int a = 5;
|
|
1575 int b = a | 4 | a; // warn: identical expr on both sides
|
|
1576 }
|
|
1577
|
|
1578 // C++
|
|
1579 bool f(void);
|
|
1580
|
|
1581 void test(bool b) {
|
|
1582 int i = 10;
|
|
1583 if (f()) { // warn: true and false branches are identical
|
|
1584 do {
|
|
1585 i--;
|
|
1586 } while (f());
|
|
1587 } else {
|
|
1588 do {
|
|
1589 i--;
|
|
1590 } while (f());
|
|
1591 }
|
|
1592 }
|
|
1593
|
|
1594 .. _alpha-core-PointerArithm:
|
|
1595
|
|
1596 alpha.core.PointerArithm (C)
|
|
1597 """"""""""""""""""""""""""""
|
|
1598 Check for pointer arithmetic on locations other than array elements.
|
|
1599
|
|
1600 .. code-block:: c
|
|
1601
|
|
1602 void test() {
|
|
1603 int x;
|
|
1604 int *p;
|
|
1605 p = &x + 1; // warn
|
|
1606 }
|
|
1607
|
|
1608 .. _alpha-core-PointerSub:
|
|
1609
|
|
1610 alpha.core.PointerSub (C)
|
|
1611 """""""""""""""""""""""""
|
|
1612 Check for pointer subtractions on two pointers pointing to different memory chunks.
|
|
1613
|
|
1614 .. code-block:: c
|
|
1615
|
|
1616 void test() {
|
|
1617 int x, y;
|
|
1618 int d = &y - &x; // warn
|
|
1619 }
|
|
1620
|
|
1621 .. _alpha-core-SizeofPtr:
|
|
1622
|
|
1623 alpha.core.SizeofPtr (C)
|
|
1624 """"""""""""""""""""""""
|
|
1625 Warn about unintended use of ``sizeof()`` on pointer expressions.
|
|
1626
|
|
1627 .. code-block:: c
|
|
1628
|
|
1629 struct s {};
|
|
1630
|
|
1631 int test(struct s *p) {
|
|
1632 return sizeof(p);
|
|
1633 // warn: sizeof(ptr) can produce an unexpected result
|
|
1634 }
|
|
1635
|
|
1636 .. _alpha-core-StackAddressAsyncEscape:
|
|
1637
|
|
1638 alpha.core.StackAddressAsyncEscape (C)
|
|
1639 """"""""""""""""""""""""""""""""""""""
|
|
1640 Check that addresses to stack memory do not escape the function that involves dispatch_after or dispatch_async.
|
|
1641 This checker is a part of ``core.StackAddressEscape``, but is temporarily disabled until some false positives are fixed.
|
|
1642
|
|
1643 .. code-block:: c
|
|
1644
|
|
1645 dispatch_block_t test_block_inside_block_async_leak() {
|
|
1646 int x = 123;
|
|
1647 void (^inner)(void) = ^void(void) {
|
|
1648 int y = x;
|
|
1649 ++y;
|
|
1650 };
|
|
1651 void (^outer)(void) = ^void(void) {
|
|
1652 int z = x;
|
|
1653 ++z;
|
|
1654 inner();
|
|
1655 };
|
|
1656 return outer; // warn: address of stack-allocated block is captured by a
|
|
1657 // returned block
|
|
1658 }
|
|
1659
|
|
1660 .. _alpha-core-TestAfterDivZero:
|
|
1661
|
|
1662 alpha.core.TestAfterDivZero (C)
|
|
1663 """""""""""""""""""""""""""""""
|
|
1664 Check for division by variable that is later compared against 0.
|
|
1665 Either the comparison is useless or there is division by zero.
|
|
1666
|
|
1667 .. code-block:: c
|
|
1668
|
|
1669 void test(int x) {
|
|
1670 var = 77 / x;
|
|
1671 if (x == 0) { } // warn
|
|
1672 }
|
|
1673
|
|
1674 alpha.cplusplus
|
|
1675 ^^^^^^^^^^^^^^^
|
|
1676
|
|
1677 .. _alpha-cplusplus-DeleteWithNonVirtualDtor:
|
|
1678
|
|
1679 alpha.cplusplus.DeleteWithNonVirtualDtor (C++)
|
|
1680 """"""""""""""""""""""""""""""""""""""""""""""
|
|
1681 Reports destructions of polymorphic objects with a non-virtual destructor in their base class.
|
|
1682
|
|
1683 .. code-block:: cpp
|
|
1684
|
|
1685 NonVirtual *create() {
|
|
1686 NonVirtual *x = new NVDerived(); // note: conversion from derived to base
|
|
1687 // happened here
|
|
1688 return x;
|
|
1689 }
|
|
1690
|
|
1691 void sink(NonVirtual *x) {
|
|
1692 delete x; // warn: destruction of a polymorphic object with no virtual
|
|
1693 // destructor
|
|
1694 }
|
|
1695
|
|
1696 .. _alpha-cplusplus-EnumCastOutOfRange:
|
|
1697
|
|
1698 alpha.cplusplus.EnumCastOutOfRange (C++)
|
|
1699 """"""""""""""""""""""""""""""""""""""""
|
|
1700 Check for integer to enumeration casts that could result in undefined values.
|
|
1701
|
|
1702 .. code-block:: cpp
|
|
1703
|
|
1704 enum TestEnum {
|
|
1705 A = 0
|
|
1706 };
|
|
1707
|
|
1708 void foo() {
|
|
1709 TestEnum t = static_cast(-1);
|
|
1710 // warn: the value provided to the cast expression is not in
|
|
1711 the valid range of values for the enum
|
|
1712
|
|
1713 .. _alpha-cplusplus-InvalidatedIterator:
|
|
1714
|
|
1715 alpha.cplusplus.InvalidatedIterator (C++)
|
|
1716 """""""""""""""""""""""""""""""""""""""""
|
|
1717 Check for use of invalidated iterators.
|
|
1718
|
|
1719 .. code-block:: cpp
|
|
1720
|
|
1721 void bad_copy_assign_operator_list1(std::list &L1,
|
|
1722 const std::list &L2) {
|
|
1723 auto i0 = L1.cbegin();
|
|
1724 L1 = L2;
|
|
1725 *i0; // warn: invalidated iterator accessed
|
|
1726 }
|
|
1727
|
|
1728
|
|
1729 .. _alpha-cplusplus-IteratorRange:
|
|
1730
|
|
1731 alpha.cplusplus.IteratorRange (C++)
|
|
1732 """""""""""""""""""""""""""""""""""
|
|
1733 Check for iterators used outside their valid ranges.
|
|
1734
|
|
1735 .. code-block:: cpp
|
|
1736
|
|
1737 void simple_bad_end(const std::vector &v) {
|
|
1738 auto i = v.end();
|
|
1739 *i; // warn: iterator accessed outside of its range
|
|
1740 }
|
|
1741
|
|
1742 .. _alpha-cplusplus-MismatchedIterator:
|
|
1743
|
|
1744 alpha.cplusplus.MismatchedIterator (C++)
|
|
1745 """"""""""""""""""""""""""""""""""""""""
|
|
1746 Check for use of iterators of different containers where iterators of the same container are expected.
|
|
1747
|
|
1748 .. code-block:: cpp
|
|
1749
|
|
1750 void bad_insert3(std::vector &v1, std::vector &v2) {
|
|
1751 v2.insert(v1.cbegin(), v2.cbegin(), v2.cend()); // warn: container accessed
|
|
1752 // using foreign
|
|
1753 // iterator argument
|
|
1754 v1.insert(v1.cbegin(), v1.cbegin(), v2.cend()); // warn: iterators of
|
|
1755 // different containers
|
|
1756 // used where the same
|
|
1757 // container is
|
|
1758 // expected
|
|
1759 v1.insert(v1.cbegin(), v2.cbegin(), v1.cend()); // warn: iterators of
|
|
1760 // different containers
|
|
1761 // used where the same
|
|
1762 // container is
|
|
1763 // expected
|
|
1764 }
|
|
1765
|
|
1766 .. _alpha-cplusplus-MisusedMovedObject:
|
|
1767
|
|
1768 alpha.cplusplus.MisusedMovedObject (C++)
|
|
1769 """"""""""""""""""""""""""""""""""""""""
|
|
1770 Method calls on a moved-from object and copying a moved-from object will be reported.
|
|
1771
|
|
1772
|
|
1773 .. code-block:: cpp
|
|
1774
|
|
1775 struct A {
|
|
1776 void foo() {}
|
|
1777 };
|
|
1778
|
|
1779 void f() {
|
|
1780 A a;
|
|
1781 A b = std::move(a); // note: 'a' became 'moved-from' here
|
|
1782 a.foo(); // warn: method call on a 'moved-from' object 'a'
|
|
1783 }
|
|
1784
|
|
1785 alpha.deadcode
|
|
1786 ^^^^^^^^^^^^^^
|
|
1787 .. _alpha-deadcode-UnreachableCode:
|
|
1788
|
|
1789 alpha.deadcode.UnreachableCode (C, C++)
|
|
1790 """""""""""""""""""""""""""""""""""""""
|
|
1791 Check unreachable code.
|
|
1792
|
|
1793 .. code-block:: cpp
|
|
1794
|
|
1795 // C
|
|
1796 int test() {
|
|
1797 int x = 1;
|
|
1798 while(x);
|
|
1799 return x; // warn
|
|
1800 }
|
|
1801
|
|
1802 // C++
|
|
1803 void test() {
|
|
1804 int a = 2;
|
|
1805
|
|
1806 while (a > 1)
|
|
1807 a--;
|
|
1808
|
|
1809 if (a > 1)
|
|
1810 a++; // warn
|
|
1811 }
|
|
1812
|
|
1813 // Objective-C
|
|
1814 void test(id x) {
|
|
1815 return;
|
|
1816 [x retain]; // warn
|
|
1817 }
|
|
1818
|
|
1819 alpha.llvm
|
|
1820 ^^^^^^^^^^
|
|
1821
|
|
1822 .. _alpha-llvm-Conventions:
|
|
1823
|
|
1824 alpha.llvm.Conventions
|
|
1825 """"""""""""""""""""""
|
|
1826
|
|
1827 Check code for LLVM codebase conventions:
|
|
1828
|
|
1829 * A StringRef should not be bound to a temporary std::string whose lifetime is shorter than the StringRef's.
|
|
1830 * Clang AST nodes should not have fields that can allocate memory.
|
|
1831
|
|
1832
|
|
1833 alpha.osx
|
|
1834 ^^^^^^^^^
|
|
1835
|
|
1836 .. _alpha-osx-cocoa-DirectIvarAssignment:
|
|
1837
|
|
1838 alpha.osx.cocoa.DirectIvarAssignment (ObjC)
|
|
1839 """""""""""""""""""""""""""""""""""""""""""
|
|
1840 Check for direct assignments to instance variables.
|
|
1841
|
|
1842
|
|
1843 .. code-block:: objc
|
|
1844
|
|
1845 @interface MyClass : NSObject {}
|
|
1846 @property (readonly) id A;
|
|
1847 - (void) foo;
|
|
1848 @end
|
|
1849
|
|
1850 @implementation MyClass
|
|
1851 - (void) foo {
|
|
1852 _A = 0; // warn
|
|
1853 }
|
|
1854 @end
|
|
1855
|
|
1856 .. _alpha-osx-cocoa-DirectIvarAssignmentForAnnotatedFunctions:
|
|
1857
|
|
1858 alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions (ObjC)
|
|
1859 """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
1860 Check for direct assignments to instance variables in
|
|
1861 the methods annotated with ``objc_no_direct_instance_variable_assignment``.
|
|
1862
|
|
1863 .. code-block:: objc
|
|
1864
|
|
1865 @interface MyClass : NSObject {}
|
|
1866 @property (readonly) id A;
|
|
1867 - (void) fAnnotated __attribute__((
|
|
1868 annotate("objc_no_direct_instance_variable_assignment")));
|
|
1869 - (void) fNotAnnotated;
|
|
1870 @end
|
|
1871
|
|
1872 @implementation MyClass
|
|
1873 - (void) fAnnotated {
|
|
1874 _A = 0; // warn
|
|
1875 }
|
|
1876 - (void) fNotAnnotated {
|
|
1877 _A = 0; // no warn
|
|
1878 }
|
|
1879 @end
|
|
1880
|
|
1881
|
|
1882 .. _alpha-osx-cocoa-InstanceVariableInvalidation:
|
|
1883
|
|
1884 alpha.osx.cocoa.InstanceVariableInvalidation (ObjC)
|
|
1885 """""""""""""""""""""""""""""""""""""""""""""""""""
|
|
1886 Check that the invalidatable instance variables are
|
|
1887 invalidated in the methods annotated with objc_instance_variable_invalidator.
|
|
1888
|
|
1889 .. code-block:: objc
|
|
1890
|
|
1891 @protocol Invalidation <NSObject>
|
|
1892 - (void) invalidate
|
|
1893 __attribute__((annotate("objc_instance_variable_invalidator")));
|
|
1894 @end
|
|
1895
|
|
1896 @interface InvalidationImpObj : NSObject <Invalidation>
|
|
1897 @end
|
|
1898
|
|
1899 @interface SubclassInvalidationImpObj : InvalidationImpObj {
|
|
1900 InvalidationImpObj *var;
|
|
1901 }
|
|
1902 - (void)invalidate;
|
|
1903 @end
|
|
1904
|
|
1905 @implementation SubclassInvalidationImpObj
|
|
1906 - (void) invalidate {}
|
|
1907 @end
|
|
1908 // warn: var needs to be invalidated or set to nil
|
|
1909
|
|
1910 .. _alpha-osx-cocoa-MissingInvalidationMethod:
|
|
1911
|
|
1912 alpha.osx.cocoa.MissingInvalidationMethod (ObjC)
|
|
1913 """"""""""""""""""""""""""""""""""""""""""""""""
|
|
1914 Check that the invalidation methods are present in classes that contain invalidatable instance variables.
|
|
1915
|
|
1916 .. code-block:: objc
|
|
1917
|
|
1918 @protocol Invalidation <NSObject>
|
|
1919 - (void)invalidate
|
|
1920 __attribute__((annotate("objc_instance_variable_invalidator")));
|
|
1921 @end
|
|
1922
|
|
1923 @interface NeedInvalidation : NSObject <Invalidation>
|
|
1924 @end
|
|
1925
|
|
1926 @interface MissingInvalidationMethodDecl : NSObject {
|
|
1927 NeedInvalidation *Var; // warn
|
|
1928 }
|
|
1929 @end
|
|
1930
|
|
1931 @implementation MissingInvalidationMethodDecl
|
|
1932 @end
|
|
1933
|
|
1934 .. _alpha-osx-cocoa-localizability-PluralMisuseChecker:
|
|
1935
|
|
1936 alpha.osx.cocoa.localizability.PluralMisuseChecker (ObjC)
|
|
1937 """""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
|
1938 Warns against using one vs. many plural pattern in code when generating localized strings.
|
|
1939
|
|
1940 .. code-block:: objc
|
|
1941
|
|
1942 NSString *reminderText =
|
|
1943 NSLocalizedString(@"None", @"Indicates no reminders");
|
|
1944 if (reminderCount == 1) {
|
|
1945 // Warning: Plural cases are not supported across all languages.
|
|
1946 // Use a .stringsdict file instead
|
|
1947 reminderText =
|
|
1948 NSLocalizedString(@"1 Reminder", @"Indicates single reminder");
|
|
1949 } else if (reminderCount >= 2) {
|
|
1950 // Warning: Plural cases are not supported across all languages.
|
|
1951 // Use a .stringsdict file instead
|
|
1952 reminderText =
|
|
1953 [NSString stringWithFormat:
|
|
1954 NSLocalizedString(@"%@ Reminders", @"Indicates multiple reminders"),
|
|
1955 reminderCount];
|
|
1956 }
|
|
1957
|
|
1958 alpha.security
|
|
1959 ^^^^^^^^^^^^^^
|
173
|
1960
|
|
1961
|
|
1962 alpha.security.cert
|
|
1963 ^^^^^^^^^^^^^^^^^^^
|
|
1964
|
|
1965 SEI CERT checkers which tries to find errors based on their `C coding rules <https://wiki.sei.cmu.edu/confluence/display/c/2+Rules>`_.
|
|
1966
|
|
1967 .. _alpha-security-cert-pos-checkers:
|
|
1968
|
|
1969 alpha.security.cert.pos
|
|
1970 ^^^^^^^^^^^^^^^^^^^^^^^
|
|
1971
|
|
1972 SEI CERT checkers of `POSIX C coding rules <https://wiki.sei.cmu.edu/confluence/pages/viewpage.action?pageId=87152405>`_.
|
|
1973
|
|
1974 .. _alpha-security-cert-pos-34c:
|
|
1975
|
|
1976 alpha.security.cert.pos.34c
|
|
1977 """""""""""""""""""""""""""
|
|
1978 Finds calls to the ``putenv`` function which pass a pointer to an automatic variable as the argument.
|
|
1979
|
|
1980 .. code-block:: c
|
|
1981
|
|
1982 int func(const char *var) {
|
|
1983 char env[1024];
|
|
1984 int retval = snprintf(env, sizeof(env),"TEST=%s", var);
|
|
1985 if (retval < 0 || (size_t)retval >= sizeof(env)) {
|
|
1986 /* Handle error */
|
|
1987 }
|
|
1988
|
|
1989 return putenv(env); // putenv function should not be called with auto variables
|
|
1990 }
|
|
1991
|
150
|
1992 .. _alpha-security-ArrayBound:
|
|
1993
|
|
1994 alpha.security.ArrayBound (C)
|
|
1995 """""""""""""""""""""""""""""
|
|
1996 Warn about buffer overflows (older checker).
|
|
1997
|
|
1998 .. code-block:: c
|
|
1999
|
|
2000 void test() {
|
|
2001 char *s = "";
|
|
2002 char c = s[1]; // warn
|
|
2003 }
|
|
2004
|
|
2005 struct seven_words {
|
|
2006 int c[7];
|
|
2007 };
|
|
2008
|
|
2009 void test() {
|
|
2010 struct seven_words a, *p;
|
|
2011 p = &a;
|
|
2012 p[0] = a;
|
|
2013 p[1] = a;
|
|
2014 p[2] = a; // warn
|
|
2015 }
|
|
2016
|
|
2017 // note: requires unix.Malloc or
|
|
2018 // alpha.unix.MallocWithAnnotations checks enabled.
|
|
2019 void test() {
|
|
2020 int *p = malloc(12);
|
|
2021 p[3] = 4; // warn
|
|
2022 }
|
|
2023
|
|
2024 void test() {
|
|
2025 char a[2];
|
|
2026 int *b = (int*)a;
|
|
2027 b[1] = 3; // warn
|
|
2028 }
|
|
2029
|
|
2030 .. _alpha-security-ArrayBoundV2:
|
|
2031
|
|
2032 alpha.security.ArrayBoundV2 (C)
|
|
2033 """""""""""""""""""""""""""""""
|
|
2034 Warn about buffer overflows (newer checker).
|
|
2035
|
|
2036 .. code-block:: c
|
|
2037
|
|
2038 void test() {
|
|
2039 char *s = "";
|
|
2040 char c = s[1]; // warn
|
|
2041 }
|
|
2042
|
|
2043 void test() {
|
|
2044 int buf[100];
|
|
2045 int *p = buf;
|
|
2046 p = p + 99;
|
|
2047 p[1] = 1; // warn
|
|
2048 }
|
|
2049
|
|
2050 // note: compiler has internal check for this.
|
|
2051 // Use -Wno-array-bounds to suppress compiler warning.
|
|
2052 void test() {
|
|
2053 int buf[100][100];
|
|
2054 buf[0][-1] = 1; // warn
|
|
2055 }
|
|
2056
|
|
2057 // note: requires alpha.security.taint check turned on.
|
|
2058 void test() {
|
|
2059 char s[] = "abc";
|
|
2060 int x = getchar();
|
|
2061 char c = s[x]; // warn: index is tainted
|
|
2062 }
|
|
2063
|
|
2064 .. _alpha-security-MallocOverflow:
|
|
2065
|
|
2066 alpha.security.MallocOverflow (C)
|
|
2067 """""""""""""""""""""""""""""""""
|
|
2068 Check for overflows in the arguments to malloc().
|
|
2069
|
|
2070 .. code-block:: c
|
|
2071
|
|
2072 void test(int n) {
|
|
2073 void *p = malloc(n * sizeof(int)); // warn
|
|
2074 }
|
|
2075
|
|
2076 void test2(int n) {
|
|
2077 if (n > 100) // gives an upper-bound
|
|
2078 return;
|
|
2079 void *p = malloc(n * sizeof(int)); // no warning
|
|
2080 }
|
|
2081
|
|
2082 .. _alpha-security-MmapWriteExec:
|
|
2083
|
|
2084 alpha.security.MmapWriteExec (C)
|
|
2085 """"""""""""""""""""""""""""""""
|
|
2086 Warn on mmap() calls that are both writable and executable.
|
|
2087
|
|
2088 .. code-block:: c
|
|
2089
|
|
2090 void test(int n) {
|
|
2091 void *c = mmap(NULL, 32, PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
2092 MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
2093 // warn: Both PROT_WRITE and PROT_EXEC flags are set. This can lead to
|
|
2094 // exploitable memory regions, which could be overwritten with malicious
|
|
2095 // code
|
|
2096 }
|
|
2097
|
|
2098 .. _alpha-security-ReturnPtrRange:
|
|
2099
|
|
2100 alpha.security.ReturnPtrRange (C)
|
|
2101 """""""""""""""""""""""""""""""""
|
|
2102 Check for an out-of-bound pointer being returned to callers.
|
|
2103
|
|
2104 .. code-block:: c
|
|
2105
|
|
2106 static int A[10];
|
|
2107
|
|
2108 int *test() {
|
|
2109 int *p = A + 10;
|
|
2110 return p; // warn
|
|
2111 }
|
|
2112
|
|
2113 int test(void) {
|
|
2114 int x;
|
|
2115 return x; // warn: undefined or garbage returned
|
|
2116 }
|
|
2117
|
|
2118 .. _alpha-security-taint-TaintPropagation:
|
|
2119
|
|
2120 alpha.security.taint.TaintPropagation (C, C++)
|
|
2121 """"""""""""""""""""""""""""""""""""""""""""""
|
|
2122 Generate taint information used by other checkers.
|
|
2123 A data is tainted when it comes from an unreliable source.
|
|
2124
|
|
2125 .. code-block:: c
|
|
2126
|
|
2127 void test() {
|
|
2128 char x = getchar(); // 'x' marked as tainted
|
|
2129 system(&x); // warn: untrusted data is passed to a system call
|
|
2130 }
|
|
2131
|
|
2132 // note: compiler internally checks if the second param to
|
|
2133 // sprintf is a string literal or not.
|
|
2134 // Use -Wno-format-security to suppress compiler warning.
|
|
2135 void test() {
|
|
2136 char s[10], buf[10];
|
|
2137 fscanf(stdin, "%s", s); // 's' marked as tainted
|
|
2138
|
|
2139 sprintf(buf, s); // warn: untrusted data as a format string
|
|
2140 }
|
|
2141
|
|
2142 void test() {
|
|
2143 size_t ts;
|
|
2144 scanf("%zd", &ts); // 'ts' marked as tainted
|
|
2145 int *p = (int *)malloc(ts * sizeof(int));
|
|
2146 // warn: untrusted data as buffer size
|
|
2147 }
|
|
2148
|
|
2149 alpha.unix
|
|
2150 ^^^^^^^^^^^
|
|
2151
|
|
2152 .. _alpha-unix-BlockInCriticalSection:
|
|
2153
|
|
2154 alpha.unix.BlockInCriticalSection (C)
|
|
2155 """""""""""""""""""""""""""""""""""""
|
|
2156 Check for calls to blocking functions inside a critical section.
|
|
2157 Applies to: ``lock, unlock, sleep, getc, fgets, read, recv, pthread_mutex_lock,``
|
|
2158 `` pthread_mutex_unlock, mtx_lock, mtx_timedlock, mtx_trylock, mtx_unlock, lock_guard, unique_lock``
|
|
2159
|
|
2160 .. code-block:: c
|
|
2161
|
|
2162 void test() {
|
|
2163 std::mutex m;
|
|
2164 m.lock();
|
|
2165 sleep(3); // warn: a blocking function sleep is called inside a critical
|
|
2166 // section
|
|
2167 m.unlock();
|
|
2168 }
|
|
2169
|
|
2170 .. _alpha-unix-Chroot:
|
|
2171
|
|
2172 alpha.unix.Chroot (C)
|
|
2173 """""""""""""""""""""
|
|
2174 Check improper use of chroot.
|
|
2175
|
|
2176 .. code-block:: c
|
|
2177
|
|
2178 void f();
|
|
2179
|
|
2180 void test() {
|
|
2181 chroot("/usr/local");
|
|
2182 f(); // warn: no call of chdir("/") immediately after chroot
|
|
2183 }
|
|
2184
|
|
2185 .. _alpha-unix-PthreadLock:
|
|
2186
|
|
2187 alpha.unix.PthreadLock (C)
|
|
2188 """"""""""""""""""""""""""
|
|
2189 Simple lock -> unlock checker.
|
|
2190 Applies to: ``pthread_mutex_lock, pthread_rwlock_rdlock, pthread_rwlock_wrlock, lck_mtx_lock, lck_rw_lock_exclusive``
|
|
2191 ``lck_rw_lock_shared, pthread_mutex_trylock, pthread_rwlock_tryrdlock, pthread_rwlock_tryrwlock, lck_mtx_try_lock,
|
|
2192 lck_rw_try_lock_exclusive, lck_rw_try_lock_shared, pthread_mutex_unlock, pthread_rwlock_unlock, lck_mtx_unlock, lck_rw_done``.
|
|
2193
|
|
2194
|
|
2195 .. code-block:: c
|
|
2196
|
|
2197 pthread_mutex_t mtx;
|
|
2198
|
|
2199 void test() {
|
|
2200 pthread_mutex_lock(&mtx);
|
|
2201 pthread_mutex_lock(&mtx);
|
|
2202 // warn: this lock has already been acquired
|
|
2203 }
|
|
2204
|
|
2205 lck_mtx_t lck1, lck2;
|
|
2206
|
|
2207 void test() {
|
|
2208 lck_mtx_lock(&lck1);
|
|
2209 lck_mtx_lock(&lck2);
|
|
2210 lck_mtx_unlock(&lck1);
|
|
2211 // warn: this was not the most recently acquired lock
|
|
2212 }
|
|
2213
|
|
2214 lck_mtx_t lck1, lck2;
|
|
2215
|
|
2216 void test() {
|
|
2217 if (lck_mtx_try_lock(&lck1) == 0)
|
|
2218 return;
|
|
2219
|
|
2220 lck_mtx_lock(&lck2);
|
|
2221 lck_mtx_unlock(&lck1);
|
|
2222 // warn: this was not the most recently acquired lock
|
|
2223 }
|
|
2224
|
|
2225 .. _alpha-unix-SimpleStream:
|
|
2226
|
|
2227 alpha.unix.SimpleStream (C)
|
|
2228 """""""""""""""""""""""""""
|
|
2229 Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fclose``
|
173
|
2230 (demo checker, the subject of the demo (`Slides <https://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf>`_ ,
|
150
|
2231 `Video <https://youtu.be/kdxlsP5QVPw>`_) by Anna Zaks and Jordan Rose presented at the
|
173
|
2232 `2012 LLVM Developers' Meeting <https://llvm.org/devmtg/2012-11/>`_).
|
150
|
2233
|
|
2234 .. code-block:: c
|
|
2235
|
|
2236 void test() {
|
|
2237 FILE *F = fopen("myfile.txt", "w");
|
|
2238 } // warn: opened file is never closed
|
|
2239
|
|
2240 void test() {
|
|
2241 FILE *F = fopen("myfile.txt", "w");
|
|
2242
|
|
2243 if (F)
|
|
2244 fclose(F);
|
|
2245
|
|
2246 fclose(F); // warn: closing a previously closed file stream
|
|
2247 }
|
|
2248
|
|
2249 .. _alpha-unix-Stream:
|
|
2250
|
|
2251 alpha.unix.Stream (C)
|
|
2252 """""""""""""""""""""
|
|
2253 Check stream handling functions: ``fopen, tmpfile, fclose, fread, fwrite, fseek, ftell, rewind, fgetpos,``
|
|
2254 ``fsetpos, clearerr, feof, ferror, fileno``.
|
|
2255
|
|
2256 .. code-block:: c
|
|
2257
|
|
2258 void test() {
|
|
2259 FILE *p = fopen("foo", "r");
|
|
2260 } // warn: opened file is never closed
|
|
2261
|
|
2262 void test() {
|
|
2263 FILE *p = fopen("foo", "r");
|
|
2264 fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
|
|
2265 fclose(p);
|
|
2266 }
|
|
2267
|
|
2268 void test() {
|
|
2269 FILE *p = fopen("foo", "r");
|
|
2270
|
|
2271 if (p)
|
|
2272 fseek(p, 1, 3);
|
|
2273 // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
|
|
2274
|
|
2275 fclose(p);
|
|
2276 }
|
|
2277
|
|
2278 void test() {
|
|
2279 FILE *p = fopen("foo", "r");
|
|
2280 fclose(p);
|
|
2281 fclose(p); // warn: already closed
|
|
2282 }
|
|
2283
|
|
2284 void test() {
|
|
2285 FILE *p = tmpfile();
|
|
2286 ftell(p); // warn: stream pointer might be NULL
|
|
2287 fclose(p);
|
|
2288 }
|
|
2289
|
|
2290
|
|
2291 .. _alpha-unix-cstring-BufferOverlap:
|
|
2292
|
|
2293 alpha.unix.cstring.BufferOverlap (C)
|
|
2294 """"""""""""""""""""""""""""""""""""
|
|
2295 Checks for overlap in two buffer arguments. Applies to: ``memcpy, mempcpy``.
|
|
2296
|
|
2297 .. code-block:: c
|
|
2298
|
|
2299 void test() {
|
|
2300 int a[4] = {0};
|
|
2301 memcpy(a + 2, a + 1, 8); // warn
|
|
2302 }
|
|
2303
|
|
2304 .. _alpha-unix-cstring-NotNullTerminated:
|
|
2305
|
|
2306 alpha.unix.cstring.NotNullTerminated (C)
|
|
2307 """"""""""""""""""""""""""""""""""""""""
|
|
2308 Check for arguments which are not null-terminated strings; applies to: ``strlen, strnlen, strcpy, strncpy, strcat, strncat``.
|
|
2309
|
|
2310 .. code-block:: c
|
|
2311
|
|
2312 void test() {
|
|
2313 int y = strlen((char *)&test); // warn
|
|
2314 }
|
|
2315
|
|
2316 .. _alpha-unix-cstring-OutOfBounds:
|
|
2317
|
|
2318 alpha.unix.cstring.OutOfBounds (C)
|
|
2319 """"""""""""""""""""""""""""""""""
|
|
2320 Check for out-of-bounds access in string functions; applies to:`` strncopy, strncat``.
|
|
2321
|
|
2322
|
|
2323 .. code-block:: c
|
|
2324
|
|
2325 void test() {
|
|
2326 int y = strlen((char *)&test); // warn
|
|
2327 }
|
|
2328
|
|
2329 .. _alpha-nondeterminism-PointerIteration:
|
|
2330
|
|
2331 alpha.nondeterminism.PointerIteration (C++)
|
|
2332 """""""""""""""""""""""""""""""""""""""""""
|
|
2333 Check for non-determinism caused by iterating unordered containers of pointers.
|
|
2334
|
|
2335 .. code-block:: c
|
|
2336
|
|
2337 void test() {
|
|
2338 int a = 1, b = 2;
|
|
2339 std::unordered_set<int *> UnorderedPtrSet = {&a, &b};
|
|
2340
|
|
2341 for (auto i : UnorderedPtrSet) // warn
|
|
2342 f(i);
|
|
2343 }
|
|
2344
|
|
2345 .. _alpha-nondeterminism-PointerSorting:
|
|
2346
|
|
2347 alpha.nondeterminism.PointerSorting (C++)
|
|
2348 """""""""""""""""""""""""""""""""""""""""
|
|
2349 Check for non-determinism caused by sorting of pointers.
|
|
2350
|
|
2351 .. code-block:: c
|
|
2352
|
|
2353 void test() {
|
|
2354 int a = 1, b = 2;
|
|
2355 std::vector<int *> V = {&a, &b};
|
|
2356 std::sort(V.begin(), V.end()); // warn
|
|
2357 }
|
|
2358
|
|
2359
|
|
2360 Debug Checkers
|
|
2361 ---------------
|
|
2362
|
|
2363 .. _debug-checkers:
|
|
2364
|
|
2365
|
|
2366 debug
|
|
2367 ^^^^^
|
|
2368
|
|
2369 Checkers used for debugging the analyzer.
|
|
2370 :doc:`developer-docs/DebugChecks` page contains a detailed description.
|
|
2371
|
|
2372 .. _debug-AnalysisOrder:
|
|
2373
|
|
2374 debug.AnalysisOrder
|
|
2375 """""""""""""""""""
|
|
2376 Print callbacks that are called during analysis in order.
|
|
2377
|
|
2378 .. _debug-ConfigDumper:
|
|
2379
|
|
2380 debug.ConfigDumper
|
|
2381 """"""""""""""""""
|
|
2382 Dump config table.
|
|
2383
|
|
2384 .. _debug-DumpCFG Display:
|
|
2385
|
|
2386 debug.DumpCFG Display
|
|
2387 """""""""""""""""""""
|
|
2388 Control-Flow Graphs.
|
|
2389
|
|
2390 .. _debug-DumpCallGraph:
|
|
2391
|
|
2392 debug.DumpCallGraph
|
|
2393 """""""""""""""""""
|
|
2394 Display Call Graph.
|
|
2395
|
|
2396 .. _debug-DumpCalls:
|
|
2397
|
|
2398 debug.DumpCalls
|
|
2399 """""""""""""""
|
|
2400 Print calls as they are traversed by the engine.
|
|
2401
|
|
2402 .. _debug-DumpDominators:
|
|
2403
|
|
2404 debug.DumpDominators
|
|
2405 """"""""""""""""""""
|
|
2406 Print the dominance tree for a given CFG.
|
|
2407
|
|
2408 .. _debug-DumpLiveVars:
|
|
2409
|
|
2410 debug.DumpLiveVars
|
|
2411 """"""""""""""""""
|
|
2412 Print results of live variable analysis.
|
|
2413
|
|
2414 .. _debug-DumpTraversal:
|
|
2415
|
|
2416 debug.DumpTraversal
|
|
2417 """""""""""""""""""
|
|
2418 Print branch conditions as they are traversed by the engine.
|
|
2419
|
|
2420 .. _debug-ExprInspection:
|
|
2421
|
|
2422 debug.ExprInspection
|
|
2423 """"""""""""""""""""
|
|
2424 Check the analyzer's understanding of expressions.
|
|
2425
|
|
2426 .. _debug-Stats:
|
|
2427
|
|
2428 debug.Stats
|
|
2429 """""""""""
|
|
2430 Emit warnings with analyzer statistics.
|
|
2431
|
|
2432 .. _debug-TaintTest:
|
|
2433
|
|
2434 debug.TaintTest
|
|
2435 """""""""""""""
|
|
2436 Mark tainted symbols as such.
|
|
2437
|
|
2438 .. _debug-ViewCFG:
|
|
2439
|
|
2440 debug.ViewCFG
|
|
2441 """""""""""""
|
|
2442 View Control-Flow Graphs using GraphViz.
|
|
2443
|
|
2444 .. _debug-ViewCallGraph:
|
|
2445
|
|
2446 debug.ViewCallGraph
|
|
2447 """""""""""""""""""
|
|
2448 View Call Graph using GraphViz.
|
|
2449
|
|
2450 .. _debug-ViewExplodedGraph:
|
|
2451
|
|
2452 debug.ViewExplodedGraph
|
|
2453 """""""""""""""""""""""
|
|
2454 View Exploded Graphs using GraphViz.
|
|
2455
|