Commit | Line | Data |
---|---|---|
34e49164 C |
1 | // **************************************************************************** |
2 | // Prelude | |
3 | // **************************************************************************** | |
4 | ||
5 | // Note: some isomorphisms are handled in the engine directly because they | |
6 | // require special support. They can not be easily described with a | |
7 | // XX <=> YY. But some of them have names, so they can be disabled, as for | |
8 | // any other isomorphism rule. That also means that those names can not | |
9 | // be used for regular isomorphism rule. Those reserved rule names are: | |
10 | // - optional_storage | |
11 | // - optional_qualifier | |
12 | // - value_format | |
13 | // See parse_cocci.ml, pattern.ml, transformation.ml. | |
14 | ||
15 | ||
16 | // Note: the order of the rules has some importance. As we don't do a fixpoint, | |
17 | // changing the order may impact the result. For instance, if we have | |
18 | // | |
19 | // iso1 = x+y <=> y+x | |
20 | // iso2 = i++ <=> i=i+1; | |
21 | // | |
22 | // and if | |
23 | // in SP we have i++; | |
24 | // in C we have i=1+i; | |
25 | // | |
26 | // Does the SP matches the C ? | |
27 | // - Yes if iso2 precedes iso1 in this file, | |
28 | // - No otherwise. | |
29 | ||
30 | ||
31 | // **************************************************************************** | |
32 | // Standard C isomorphisms | |
33 | // **************************************************************************** | |
34 | ||
35 | // --------------------------------------------------------------------------- | |
36 | // Spacing (include comments) isomorphisms | |
37 | // --------------------------------------------------------------------------- | |
38 | // They are handled at lex time. | |
39 | ||
40 | // --------------------------------------------------------------------------- | |
41 | // Dataflow isomorphisms (copy propagation, assignments) | |
42 | // --------------------------------------------------------------------------- | |
43 | // They are handled in engine (TODO). | |
44 | ||
45 | ||
46 | // --------------------------------------------------------------------------- | |
47 | // Iso-by-absence (optional qualifier, storage, sign, cast) isomorphisms | |
48 | // --------------------------------------------------------------------------- | |
49 | // Some of them are handled in cocci_vs_c. Some of them handled here. | |
50 | ||
51 | ||
52 | // We would like that | |
53 | // chip = (ak4117_t *)snd_magic_kcalloc(ak4117_t, 0, GFP_KERNEL); | |
54 | // also matches | |
55 | // X = snd_magic_kcalloc(T, 0, C) | |
56 | // | |
57 | // For the moment because the iso is (T) E => E and not <=>, it forces | |
58 | // us to rewrite the SP as X = (T) snd_magic_kcalloc(T, 0, C) | |
59 | ||
60 | Expression | |
61 | @ drop_cast @ | |
62 | expression E; | |
63 | pure type T; | |
64 | @@ | |
65 | ||
66 | // in the following, the space at the beginning of the line is very important! | |
67 | (T)E => E | |
68 | ||
69 | Type | |
70 | @ add_signed @ | |
71 | @@ | |
72 | int => signed int | |
73 | ||
74 | Type | |
75 | @ add_int1 @ | |
76 | @@ | |
77 | unsigned => unsigned int | |
78 | ||
79 | Type | |
80 | @ add_int2 @ | |
81 | @@ | |
82 | signed => signed int | |
83 | ||
84 | ||
85 | // --------------------------------------------------------------------------- | |
86 | // Field isomorphisms | |
87 | // --------------------------------------------------------------------------- | |
88 | // Dereferences | |
89 | ||
90 | ||
91 | // Those iso were introduced for the 'generic program matching' paper, | |
92 | // with sgrep. The idea is that when we want to detect bugs, | |
93 | // we want to detect something like free(X) ... *X | |
94 | // meaning that you try to access something that have been freed. | |
95 | // But *X is not the only way to deference X, there is also | |
96 | // X->fld, hence those iso. | |
97 | ||
98 | // The following don't see like a good idea, because eg fld could be | |
99 | // instantiated in different ways in different places, meaning that the | |
100 | // two occurrences of "*E" would not refer to the same thing at all. | |
101 | // This could be addressed by making E pure, but then I think it would | |
102 | // have no purpose. | |
103 | ||
104 | // Expression | |
105 | // @@ | |
106 | // expression E; | |
107 | // identifier fld; | |
108 | // @@ | |
109 | // | |
110 | // *E => E->fld | |
111 | // | |
112 | // Expression | |
113 | // @@ | |
114 | // expression E; | |
115 | // identifier fld; | |
116 | // @@ | |
117 | // | |
118 | // *E => (E)->fld | |
119 | // | |
120 | // Expression | |
121 | // @@ | |
122 | // expression E,E1; | |
123 | // @@ | |
124 | // | |
125 | // *E => E[E1] | |
126 | ||
127 | // --------------------------------------------------------------------------- | |
128 | // Typedef isomorphisms | |
129 | // --------------------------------------------------------------------------- | |
130 | // They are handled in engine. | |
131 | ||
132 | ||
133 | // --------------------------------------------------------------------------- | |
c3e37e97 | 134 | // Boolean isomorphisms for int and pointer types |
34e49164 C |
135 | // --------------------------------------------------------------------------- |
136 | ||
137 | // the space at the beginning of the line is very important! | |
138 | Expression | |
c3e37e97 C |
139 | @ not_int1 @ |
140 | int X; | |
141 | @@ | |
142 | !X => X == 0 | |
143 | ||
144 | TestExpression | |
145 | @ not_int2 @ | |
34e49164 C |
146 | int X; |
147 | @@ | |
c3e37e97 | 148 | X => X != 0 |
34e49164 C |
149 | |
150 | // the space at the beginning of the line is very important! | |
151 | Expression | |
c3e37e97 C |
152 | @ not_ptr1 @ |
153 | expression *X; | |
154 | @@ | |
155 | !X => X == NULL | |
156 | ||
157 | TestExpression | |
158 | @ not_ptr2 @ | |
159 | expression *X; | |
160 | @@ | |
161 | X => X != NULL | |
162 | ||
163 | // --------------------------------------------------------------------------- | |
164 | // Boolean isomorphisms | |
165 | // --------------------------------------------------------------------------- | |
166 | ||
167 | Expression | |
168 | @commeq@ | |
169 | expression E; | |
170 | constant C; | |
171 | @@ | |
172 | ||
173 | E == C <=> C == E | |
174 | ||
175 | Expression | |
176 | @commneq@ | |
177 | expression E; | |
178 | constant C; | |
34e49164 | 179 | @@ |
c3e37e97 C |
180 | |
181 | E != C <=> C != E | |
34e49164 C |
182 | |
183 | Expression | |
184 | @ is_zero @ | |
185 | expression X; | |
186 | @@ | |
c3e37e97 | 187 | X == 0 => !X |
34e49164 | 188 | |
c3e37e97 C |
189 | // X should be a test expression, but X!=0 doesn't have to be one |
190 | // not nice at all... ToTestExpression sets everything after the first | |
191 | // pattern in the iso rule to be TestExpression | |
192 | ToTestExpression | |
34e49164 C |
193 | @ isnt_zero @ |
194 | expression X; | |
195 | @@ | |
c3e37e97 C |
196 | X != 0 => X |
197 | ||
198 | Expression | |
199 | @ is_null @ | |
200 | expression X; | |
201 | @@ | |
202 | X == NULL => !X | |
203 | ||
204 | ToTestExpression | |
205 | @ isnt_null1 @ | |
206 | expression X; | |
207 | @@ | |
208 | X != NULL => X | |
209 | ||
210 | // --------------------------------------------------------------------------- | |
211 | // Bit operations | |
212 | // --------------------------------------------------------------------------- | |
34e49164 C |
213 | |
214 | Expression | |
215 | @ bitor_comm @ | |
216 | expression X,Y; | |
217 | @@ | |
218 | X | Y => Y | X | |
219 | ||
220 | Expression | |
221 | @ bitand_comm @ | |
222 | expression X,Y; | |
223 | @@ | |
224 | X & Y => Y & X | |
225 | ||
faf9a90c C |
226 | // only if side effect free in theory, perhaps makes no sense |
227 | // Expression | |
228 | // @ and_comm @ | |
229 | // expression X,Y; | |
230 | // @@ | |
231 | // X && Y => Y && X | |
34e49164 | 232 | |
faf9a90c C |
233 | // Expression |
234 | // @ or_comm @ | |
235 | // expression X,Y; | |
236 | // @@ | |
237 | // X || Y => Y || X | |
34e49164 C |
238 | |
239 | ||
240 | // --------------------------------------------------------------------------- | |
241 | // Arithmetic isomorphisms | |
242 | // --------------------------------------------------------------------------- | |
243 | //todo: require check side-effect free expression | |
244 | ||
245 | Expression | |
246 | @ plus_comm @ | |
247 | expression X, Y; | |
248 | @@ | |
249 | X + Y => Y + X | |
250 | ||
251 | ||
252 | // needed in kcalloc CE, where have a -kzalloc(c * sizeof(T), E) | |
253 | Expression | |
254 | @ mult_comm @ | |
255 | expression X, Y; | |
256 | @@ | |
257 | X * Y => Y * X | |
258 | ||
259 | Expression | |
260 | @ plus_assoc @ | |
261 | expression X, Y, Z; | |
262 | @@ | |
263 | // note space before ( | |
264 | (X + Y) + Z <=> X + Y + Z | |
265 | ||
266 | Expression | |
267 | @ minus_assoc @ | |
268 | expression X, Y, Z; | |
269 | @@ | |
270 | ||
271 | (X - Y) - Z <=> X - Y - Z | |
272 | ||
273 | Expression | |
274 | @ plus_minus_assoc1 @ | |
275 | expression X, Y, Z; | |
276 | @@ | |
277 | ||
278 | (X + Y) - Z <=> X + Y - Z | |
279 | ||
280 | Expression | |
281 | @ plus_minus_assoc2 @ | |
282 | expression X, Y, Z; | |
283 | @@ | |
284 | ||
285 | (X - Y) + Z <=> X - Y + Z | |
286 | ||
287 | Expression | |
288 | @ times_assoc @ | |
289 | expression X, Y, Z; | |
290 | @@ | |
291 | ||
292 | (X * Y) * Z <=> X * Y * Z | |
293 | ||
294 | Expression | |
295 | @ div_assoc @ | |
296 | expression X, Y, Z; | |
297 | @@ | |
298 | ||
299 | (X / Y) / Z <=> X / Y / Z | |
300 | ||
301 | Expression | |
302 | @ times_div_assoc1 @ | |
303 | expression X, Y, Z; | |
304 | @@ | |
305 | ||
306 | (X * Y) / Z <=> X * Y / Z | |
307 | ||
308 | Expression | |
309 | @ times_div_assoc2 @ | |
310 | expression X, Y, Z; | |
311 | @@ | |
312 | ||
313 | (X / Y) * Z <=> X / Y * Z | |
314 | ||
315 | // --------------------------------------------------------------------------- | |
316 | // Relational isomorphisms | |
317 | // --------------------------------------------------------------------------- | |
318 | ||
319 | Expression | |
320 | @ gtr_lss @ | |
321 | expression X, Y; | |
322 | @@ | |
323 | X < Y <=> Y > X | |
324 | ||
708f4980 C |
325 | Expression |
326 | @ gtr_lss_eq @ | |
327 | expression X, Y; | |
328 | @@ | |
329 | X <= Y <=> Y >= X | |
330 | ||
34e49164 C |
331 | // --------------------------------------------------------------------------- |
332 | // Increment isomorphisms | |
333 | // --------------------------------------------------------------------------- | |
334 | ||
335 | // equivalences between i++, +=1, etc. | |
336 | // note: there is an addition in this SP. | |
337 | Statement | |
338 | @ inc @ | |
339 | identifier i; | |
340 | @@ | |
341 | i++; <=> ++i; <=> i+=1; <=> i=i+1; | |
342 | ||
343 | // I would like to avoid the following rule, but we cant transform a ++i | |
344 | // in i++ everywhere. We can do it only when the instruction is alone, | |
345 | // such as when there is not stuff around it (not as in x = i++) That's why in | |
346 | // the previous iso, we have explicitely force the i++ do be alone with | |
347 | // the ';'. But unfortunately in the last expression of the for there is | |
348 | // no ';' so the previous rule cannot be applied, hence this special | |
349 | // case. | |
350 | ||
351 | Statement | |
352 | @ for_inc @ | |
353 | expression X, Y; | |
354 | statement S; | |
355 | identifier i; | |
356 | @@ | |
357 | for(X;Y;i++) S <=> for(X;Y;++i) S | |
358 | ||
7f004419 C |
359 | // **************************************************************************** |
360 | // gcc specific isomorphisms | |
361 | // **************************************************************************** | |
362 | ||
363 | // likely and unlikely are used to give hints to gcc to improve performance. | |
364 | ||
365 | Expression | |
9f8e26f4 | 366 | @ unlikely @ |
7f004419 C |
367 | expression E; |
368 | @@ | |
369 | ||
370 | unlikely(E) <=> likely(E) => E | |
371 | ||
372 | // --------------------------------------------------------------------------- | |
373 | // Parenthesis isomorphisms | |
374 | // --------------------------------------------------------------------------- | |
375 | //Expression | |
376 | //@@ expression E; @@ | |
377 | // E => (E) | |
378 | //// E => ((E)) | |
379 | ||
380 | // todo: isomorphism avec les () around ? cf sizeof 3. | |
381 | // (E) => E with some conditions. | |
382 | ||
383 | Expression | |
384 | @ paren @ | |
385 | expression E; | |
386 | @@ | |
387 | ||
388 | (E) => E | |
389 | ||
34e49164 C |
390 | // --------------------------------------------------------------------------- |
391 | // Statement isomorphisms | |
392 | // --------------------------------------------------------------------------- | |
393 | ||
34e49164 C |
394 | // --------------------------------------------------------------------------- |
395 | // Value isomorphisms | |
396 | // --------------------------------------------------------------------------- | |
397 | ||
398 | // There is also equal_c_int in cocci_vs_c to dealing with other | |
399 | // integer decimal/hexadecimal isomorphisms. | |
400 | // an argexpression applies only at top level, in the argument of a | |
401 | // function call, or on the right-hand side of an assignment | |
402 | ArgExpression | |
403 | @ zero_multiple_format @ | |
404 | @@ | |
405 | 0 => '\0' | |
406 | ||
c3e37e97 C |
407 | // ---------------- |
408 | // If | |
409 | // ---------------- | |
410 | ||
34e49164 C |
411 | // **************************************************************************** |
412 | // if structure isomorphisms | |
413 | // **************************************************************************** | |
414 | ||
c3e37e97 | 415 | // these are after the above so that the introduced negation will distribute |
34e49164 C |
416 | // properly over the argument to likely/unlikely |
417 | ||
418 | Statement | |
419 | @ neg_if @ | |
420 | expression X; | |
421 | statement S1, S2; | |
422 | @@ | |
423 | if (X) S1 else S2 => if (!X) S2 else S1 | |
424 | ||
002099fc C |
425 | Statement |
426 | @ ne_if @ | |
427 | expression E1, E2; | |
428 | statement S1, S2; | |
429 | @@ | |
430 | if (E1 != E2) S1 else S2 => if (E1 == E2) S2 else S1 | |
431 | ||
34e49164 C |
432 | Statement |
433 | @ drop_else @ | |
434 | expression E; | |
435 | statement S1; | |
436 | pure statement S2; | |
437 | @@ | |
438 | ||
439 | if (E) S1 else S2 => if (E) S1 | |
440 | ||
441 | Expression | |
442 | @ neg_if_exp @ | |
443 | expression E1, E2, E3; | |
444 | @@ | |
445 | ||
446 | E1 ? E2 : E3 => !E1 ? E3 : E2 | |
447 | ||
448 | ||
449 | // if (X) Y else Z <=> X ? Y : Z sometimes. | |
450 | ||
451 | // ---------------- | |
452 | // Loops | |
453 | // ---------------- | |
454 | ||
455 | // --------------------------------------------------------------------------- | |
456 | // Optional initializers | |
457 | // --------------------------------------------------------------------------- | |
458 | // this is not safe when the declaration is replaced | |
459 | // attempt to indicate that by requiring that Z is context | |
460 | // no optional static/extern for isos | |
461 | Declaration | |
462 | @ decl_init @ | |
463 | type T; | |
464 | context identifier Z; | |
465 | @@ | |
466 | T Z; => T Z = ...; | |
467 | ||
468 | Declaration | |
469 | @ const_decl_init @ | |
470 | type T; | |
471 | identifier Z; | |
472 | constant C; | |
473 | @@ | |
474 | T Z; => T Z = C; | |
475 | ||
476 | Declaration | |
477 | @ extern_decl_init @ | |
478 | type T; | |
479 | context identifier Z; | |
480 | @@ | |
481 | extern T Z; => extern T Z = ...; | |
482 | ||
483 | Declaration | |
484 | @ const_extern_decl_init @ | |
485 | type T; | |
486 | identifier Z; | |
487 | constant C; | |
488 | @@ | |
489 | extern T Z; => extern T Z = C; | |
490 | ||
491 | Declaration | |
492 | @ static_decl_init @ | |
493 | type T; | |
494 | context identifier Z; | |
495 | @@ | |
496 | static T Z; => static T Z = ...; | |
497 | ||
498 | Declaration | |
499 | @ const_static_decl_init @ | |
500 | type T; | |
501 | identifier Z; | |
502 | constant C; | |
503 | @@ | |
504 | static T Z; => static T Z = C; | |
505 | ||
506 | // --------------------------------------------------------------------------- | |
507 | // Branch (or compound) isomorphisms | |
508 | // --------------------------------------------------------------------------- | |
509 | // maybe a cocci patch should require something that looks like what is on | |
510 | // the left above to occur in a if or while | |
511 | ||
512 | // could worry that this has to be a simple statement, but this should work | |
513 | // better as it allows + code on S | |
514 | Statement | |
515 | @ braces1 @ | |
516 | statement S; | |
517 | @@ | |
518 | { ... S } => S | |
519 | ||
520 | Statement | |
521 | @ braces2 @ | |
522 | statement S; | |
523 | @@ | |
524 | { ... S ... } => S | |
525 | ||
526 | Statement | |
527 | @ braces3 @ | |
528 | statement S; | |
529 | @@ | |
530 | { S ... } => S | |
531 | ||
532 | Statement | |
533 | @ braces4 @ | |
534 | statement S; | |
535 | @@ | |
536 | { S } => S | |
537 | ||
538 | Statement | |
539 | @ ret @ | |
540 | @@ | |
541 | return ...; => return; | |
542 | ||
543 | ||
544 | // --------------------------------------------------------------------------- | |
545 | // Declaration isomorphisms | |
546 | // --------------------------------------------------------------------------- | |
547 | // They are handled in engine (TODO) | |
548 | ||
549 | // int i,j,k; <=> int i; int j; int k; | |
550 | ||
551 | ||
552 | // --------------------------------------------------------------------------- | |
553 | // Affectation/initialisation isomorphism | |
554 | // --------------------------------------------------------------------------- | |
555 | // They are handled in engine. | |
556 | // 'X = Y' should also match 'type X = Y'; | |
557 | ||
34e49164 C |
558 | // --------------------------------------------------------------------------- |
559 | // Pointer/Array isomorphisms | |
560 | // --------------------------------------------------------------------------- | |
561 | ||
562 | // pointer arithmetic equivalences | |
563 | // a + x <=> a[x] | |
564 | ||
565 | // --------------------------------------------------------------------------- | |
566 | // Pointer/Field isomorphisms | |
567 | // --------------------------------------------------------------------------- | |
568 | ||
569 | Expression | |
570 | @ ptr_to_array @ | |
571 | expression E1, E2; // was pure, not sure why that's needed, not good for rule27 | |
572 | identifier fld; | |
573 | @@ | |
574 | ||
575 | E1->fld => E1[E2].fld | |
576 | ||
577 | ||
578 | ||
579 | TopLevel | |
580 | @ mkinit @ | |
581 | type T; | |
582 | pure context T E; | |
583 | identifier I; | |
584 | identifier fld; | |
585 | expression E1; | |
586 | @@ | |
587 | ||
588 | E.fld = E1; => T I = { .fld = E1, }; | |
589 | ||
590 | // --------------------------------------------------------------------------- | |
591 | // more pointer field iso | |
592 | // --------------------------------------------------------------------------- | |
593 | ||
594 | // pure means that either the whole field reference expression is dropped, | |
595 | // or E is context code and has no attached + code | |
596 | // not really... pure means matches a unitary unplussed metavariable | |
597 | // but this rule doesn't work anyway | |
598 | ||
599 | Expression | |
600 | @ fld_to_ptr @ | |
601 | type T; | |
602 | pure T E; | |
603 | pure T *E1; | |
604 | identifier fld; | |
605 | @@ | |
606 | ||
607 | E.fld => E1->fld | |
608 | ||
609 | ||
610 | // --------------------------------------------------------------------------- | |
611 | // sizeof isomorphisms | |
612 | // --------------------------------------------------------------------------- | |
613 | ||
faf9a90c C |
614 | // The following is made redundant by the paren isomorphism |
615 | // Expression | |
616 | // @ sizeof_parens @ | |
617 | // expression E; | |
618 | // @@ | |
34e49164 | 619 | |
faf9a90c | 620 | // sizeof(E) => sizeof E |
34e49164 C |
621 | |
622 | ||
623 | Expression | |
624 | @ sizeof_type_expr @ | |
625 | pure type T; // pure because we drop a metavar | |
626 | T E; | |
627 | @@ | |
628 | ||
629 | sizeof(T) => sizeof(E) | |
630 | ||
485bce71 C |
631 | // Expression |
632 | // @ fld_func_call @ | |
633 | // expression list ES; | |
634 | // identifier fld; | |
635 | // expression E; | |
636 | // @@ | |
637 | // E.fld(ES) <=> (*E.fld)(ES) | |
638 | ||
34e49164 C |
639 | |
640 | // **************************************************************************** | |
641 | // Linux specific isomorphisms | |
642 | // **************************************************************************** | |
643 | ||
644 | // Examples: many functions are equivalent/related, and one SP modifying | |
645 | // such a function should also modify the equivalent/related one. | |
646 | ||
647 | ||
648 | // --------------------------------------------------------------------------- | |
649 | // in rule18, needed ? | |
650 | // --------------------------------------------------------------------------- | |
651 | // ( | |
652 | // - test_and_set_bit(ev, &bcs->event); | |
653 | // | | |
654 | // - set_bit(ev, &bcs->event); | |
655 | // | | |
656 | // - bcs->event |= 1 << ev; // the only case that is used | |
657 | ||
658 | ||
659 | // **************************************************************************** | |
660 | // Everything that is required to be in last position, for ugly reasons ... | |
661 | // **************************************************************************** |