2014-08-29 89 views
0

我正在慢慢地學習,並通過編碼進步,所以我希望有人能夠快速查看這個函數,並告訴我是否看起來我在正確的軌道上,我如何可以做得更好,或者我可能會讓自己失敗。我對C的世界很陌生,所以請對我輕鬆 - 但要坦誠直率。strncpy和代碼的效率

void test(char *username, char *password) { 

    printf("Checking password for %s - pw: %s\n",username,password); 
    char *query1 = "SELECT password FROM logins WHERE email = '"; 
    char *query2 = "' LIMIT 1"; 

    char *querystring = malloc(strlen(query1) + strlen(username) + strlen(query2) * sizeof(char)); 

    strncpy(querystring,query1,strlen(query1)); 
    strncat(querystring,username,strlen(username)); 
    strncat(querystring,query2,strlen(query2)); 

    printf("Query string: %s\n",querystring); 

    mysql_query(mysql_con,querystring); 
    MYSQL_RES *result = mysql_store_result(mysql_con); 


    int num_fields = mysql_num_fields(result); 
    int num_rows = mysql_num_rows(result); 

    if (num_rows != 0) { 

     MYSQL_ROW row; 
     printf("Query returned %i results with %i fields\n",num_rows,num_fields); 

     row = mysql_fetch_row(result); 

     printf("Password returned: %s\n",row[0]); 

     int comparison = strncmp(password, row[0], strlen(password)); 

     if (comparison == 0) { 
      printf("Passwords match!\n"); 
     } else { 
      printf("Passwords do NOT match!\n"); 
     } 

    } else { 
     printf("No such user... Password is invalid"); 
    } 
    free(querystring); 
} 

目前,它正在...輸出:

Checking password for [email protected] - pw: 5f4dcc3b5aa765d61d8327deb882cf99 
Query string: SELECT password FROM logins WHERE email = '[email protected]' LIMIT 1 
Query returned 1 results with 1 fields 
Password returned: 5f4dcc3b5aa765d61d8327deb882cf99 
Passwords match! 

調用:

test("[email protected]","5f4dcc3b5aa765d61d8327deb882cf99"); 

我正在尋找輸入有關如何我可以與合作字符串更好,或者如果我有這樣的事情有任何不可預見的問題。我對C中的數據結構非常陌生。

+6

這個問題似乎是題外話題,因爲它是關於代碼審查(嘗試http:// codereview。stackexchange.com)。 – 2014-08-29 22:20:17

+0

,我注意到我弄糟了if語句和final else語句的格式......對不起。 – 2014-08-29 22:23:07

+3

'strncpy'和'strncat'和'malloc'被錯誤地使用。如果這段代碼似乎有效,那麼它很巧合 – 2014-08-29 22:24:27

回答

1

使用strncpy(target, source, strlen(source))保證target中的字符串不是空終止的。如果收到malloc()返回歸零內存,那麼它似乎工作,但一旦malloc()返回非歸零內存(以前分配的內存),事情會出錯。

strncat()的長度參數很簡單,它是當前(以空值終止)數據之後目標字符串中剩餘的空間量。除了不使用以空字符結尾的字符串之外,您的用法不能防止緩衝區溢出。

對於strncat() IMNSHO確實沒有很好的使用情況,對於strncpy()很少有很好的情況。如果你知道一切有多大,你可以用memmove()(或memcpy())代替。如果你不知道所有東西有多大,你不知道是否可以不截斷地進行復制。

您的malloc()調用有點奇怪:它不會爲尾部空值分配足夠的空間,它只會乘以sizeof(char)這三個項中的一個,這是不一致的,否則就是無害的。很多時候你會因爲短暫的分配而逃脫,因爲malloc()會增大規模,但是當你沒有逃避時,所有地獄都會崩潰。像valgrind這樣的工具會報告濫用分配的內存。

0

喬納森的答案解釋了代碼的那部分問題。

要解決它,你可以使用snprintf代替:

size_t space_needed = strlen(query1) + strlen(username) + strlen(query2) + 1; 
char *querystring = malloc(space_needed + 1); 
if (!query_string) 
    exit(EXIT_FAILURE); 

snprintf(query_string, space_needed, "%s%s%s", query1, username, query2); 

這樣,即使您計算長度錯了,至少你沒有得到一個緩衝區溢出。

爲避免此處的代碼重複,您有一個非標準函數asprintf,您傳遞參數併產生指向正確大小的malloc'd緩衝區的指針。當然,如果您不想依賴該函數的存在,可以編寫自己的函數版本。

這裏還有一個嚴重的問題,因爲你的代碼不能防範SQL注入(see here的解釋)。關於如何防範這一問題的適當討論可能超出了這個問題的範圍!