2011-10-07 41 views
4

某些函數有一個指針參數指向調用該函數的結果應該被存儲在哪裏,但函數在調用函數時也要求該指針指向某個用作輸入的值值 (例如輸入/輸出參數)。檢測傳遞指針到未初始化的變量

我想檢測這樣的函數被調用指向未初始化的變量的情況。 Coccinelle應該可以做到這一點,但是我爲了實現這一點而努力一點。

例的目標代碼:

#include <string.h> 
#include <stdio.h> 

static void cartoon_random_generator(int *n) 
{ 
    switch (*n) { 
    case 4: 
     *n = 4; /* http://xkcd.com/221/ */ 
     break; 
    case 9: 
     *n = 9; /* http://dilbert.com/strips/comic/2001-10-25/ */ 
     break; 
    default: 
     fprintf(stderr, "*n was not initialized before calling this function\n"); 
     break; 
    } 
} 
/* alternative links http://i.stack.imgur.com/VvTef.png and http://i.stack.imgur.com/u0iJ7.gif */ 

static void test(const char *cartoon) 
{ 
    // not ok, missing 
    { 
     int n1; 

     cartoon_random_generator(&n1); 
     printf("Random number = %d\n", n1); 
    } 

    // ok, declaration 
    { 
     int n2 = 4; 

     cartoon_random_generator(&n2); 
     printf("Random number = %d\n", n2); 
    } 

    // ok, statement 
    { 
     int n3; 

     n3 = 9; 
     cartoon_random_generator(&n3); 
     printf("Random number = %d\n", n3); 
    } 

    // both ok and not ok 
    { 
     int n4, n9; 

     n9 = 9; 
     //strcmp(cartoon, "XKCD") == 0 ? cartoon_random_generator(&n4) : cartoon_random_generator(&n9); 
     if (strcmp(cartoon, "XKCD") == 0) 
      cartoon_random_generator(&n4); 
     else 
      cartoon_random_generator(&n9); 
     printf("Random numbers = %d, %d\n", n4, n9); 
    } 
} 

我寫了下面的腳本COCCINELLE

/* It is an error to call cartoon_random_generator with an uninitialized 
    variable. Detect this. */ 


/* 
* This rule matches an OK case where the in variable is initialized when 
* declared. No action is performed for this rule other than giving p1 a value. 
*/ 
@[email protected] 
position p1; 
expression init_expression; 
identifier n; 
@@ 

int n = init_expression; 
... 
[email protected](&n) 


/* 
* This rule matches an OK case where the in variable is initialized in a 
* separate statement. No action is performed for this rule other than 
* giving p2 a value. 
*/ 
@[email protected] 
position p2; 
expression init_expression; 
identifier n; 
@@ 

int n; 
... 
n = init_expression; 
... 
[email protected](&n) 


/* If neither rule1 or rule2 have matched so far, 
* we have a variable that is uninitialized. */ 

@[email protected] 
position p3 != rule1.p1, rule2.p2; 
identifier n; 
@@ 

int n; 
... 
* [email protected](&n) 

但規則2不考慮,我不明白爲什麼。運行它給出:

$ /opt/coccinelle/bin/spatch -sp_file cartoon_random.cocci cartoon_random.c 
init_defs_builtins: /opt/coccinelle/share/coccinelle/standard.h 
warning: rule3: inherited metavariable p2 not used in the -, +, or context code 
HANDLING: cartoon_random.c 
diff = 
--- cartoon_random.c 
+++ /tmp/cocci-output-7916-8df75b-cartoon_random.c 
@@ -23,7 +23,6 @@ static void test(const char *cartoon) 
     { 
       int n1; 

-    cartoon_random_generator(&n1); 
       printf("Random number = %d\n", n1); 
     } 

@@ -40,7 +39,6 @@ static void test(const char *cartoon) 
       int n3; 

       n3 = 9; 
-    cartoon_random_generator(&n3); 
       printf("Random number = %d\n", n3); 
     } 

@@ -51,9 +49,7 @@ static void test(const char *cartoon) 
       n9 = 9; 
       //strcmp(cartoon, "XKCD") == 0 ? cartoon_random_generator(&n4) : cartoon_random_generator(&n9); 
       if (strcmp(cartoon, "XKCD") == 0) 
-      cartoon_random_generator(&n4); 
       else 
-      cartoon_random_generator(&n9); 
       printf("Random numbers = %d, %d\n", n4, n9); 
     } 
} 

回答

2

我是Coccinelle的總使用初學者,並且有意義瞭解它。你提出的問題是檢測未初始化變量的一個相當好的要求,這讓我有點研究。在做了一點研究之後(&從warning: rule3: inherited metavariable p2 not used in the -, +, or context code得到線索)使您的coccinelle腳本工作的方法之一(可能有其他/更好的方法)是將規則1和2結合使用&只使用單變量的單繼承最終規則。一些在這些線路上:

@[email protected] 
position p1; 
expression init_expression; 
identifier n; 
@@ 

(
int n = init_expression; 
| 
int n; 
... 
n = init_expression; 
) 
... 
[email protected](&n) 

@[email protected] 
position p2 != rule1.p1; 
identifier n; 
@@ 

int n; 
... 
* [email protected](&n) 

在這種情況下看到的輸出是:

$spatch -sp_file cartoon_random.cocci cartoon_random.c 
init_defs_builtins: /usr/share/coccinelle/standard.h 
HANDLING: cartoon_random.c 
diff = 
--- cartoon_random.c 
+++ /tmp/cocci-output-7916-8df75b-cartoon_random.c 
@@ -23,7 +23,6 @@ static void test(const char *cartoon) 
     { 
       int n1; 

-    cartoon_random_generator(&n1); 
       printf("Random number = %d\n", n1); 
     } 

@@ -51,9 +50,6 @@ static void test(const char *cartoon) 
       n9 = 9; 
       //strcmp(cartoon, "XKCD") == 0 ? cartoon_random_generator(&n4) : cartoon_random_generator(&n9); 
       if (strcmp(cartoon, "XKCD") == 0) 
-      cartoon_random_generator(&n4); 
       else 
         cartoon_random_generator(&n9); 
       printf("Random numbers = %d, %d\n", n4, n9); 

這是運行在FC15從Fedora的回購安裝COCCINELLE包。
希望這有助於!

+0

非常好。我真的很喜歡rule1現在更清楚地表達意圖。 – hlovdal

+0

@hlovdal:很高興能幫到你! –

1

朱莉婭也suggested以下簡單的版本

@@ 
idexpression n; 
expression E; 
@@ 

... when != n = E 
* cartoon_random_generator(&n) 

更新:更換標識與idexpression since,更好地處理不同的塊範圍。

+1

非常感謝!這將幫助我學習更多 –