【问题标题】:Efficiency of strncpy and code [closed]strncpy 和代码的效率[关闭]
【发布时间】:2014-08-29 22:19:34
【问题描述】:

我正在通过编码慢慢学习和进步,所以我希望有人可以帮我快速了解一下这个功能,并告诉我我是否走在正确的轨道上,我该如何做得更好或我可能会为失败做好准备。我是 C 世界的新手,所以请放轻松 - 但要直率和诚实。

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 jhall@futuresouth.us - pw: 5f4dcc3b5aa765d61d8327deb882cf99
Query string: SELECT password FROM logins WHERE email = 'test@blah.com' LIMIT 1
Query returned 1 results with 1 fields
Password returned: 5f4dcc3b5aa765d61d8327deb882cf99
Passwords match!

调用:

test("test@blah.com","5f4dcc3b5aa765d61d8327deb882cf99");

我正在寻找有关如何更好地处理字符串的意见,或者我的处理方式是否存在任何不可预见的问题。我对使用 C 中的数据结构非常陌生。

【问题讨论】:

  • 这个问题似乎跑题了,因为它是关于代码审查的(试试codereview.stackexchange.com)。
  • 我注意到我搞砸了 if 语句和最终 else 语句的格式...抱歉。
  • strncpystrncatmalloc 使用不正确。如果此代码似乎可以正常工作,那纯属巧合
  • 你说的不对,能不能给点意见?
  • 记得为 '\0' 分配 1 个额外的字符。另外,你可以存储strlen得到的长度并使用memcpy(这里不需要,但是更好)。

标签: c strcmp strcat strncpy


【解决方案1】:

使用strncpy(target, source, strlen(source)) 可以保证target 中的字符串不会以空值结尾。如果malloc() 可能返回归零内存,那么它似乎可以工作,但是一旦malloc() 返回非归零内存(先前分配的内存),事情就会出错。

strncat() 的长度参数很奇怪;它是当前(以空结尾的)数据之后目标字符串中剩余的空间量。您的使用,除了没有可以处理的以空字符结尾的字符串外,并不能防止缓冲区溢出。

strncat() IMNSHO 确实没有好的用例,strncpy() 也很少有好的用例。如果您知道所有内容有多大,则可以改用memmove()(或memcpy())。如果您不知道所有内容有多大,那么您不知道在不截断的情况下进行复制是否安全。

您的malloc() 调用也有点奇怪:它没有为结尾的空值分配足够的空间,并且它仅将三个术语之一乘以sizeof(char),这是不一致的,但在其他方面是无害的。很多时候你会逃脱短期分配,因为malloc() 将大小向上舍入,但如果你不逃脱,所有地狱都会崩溃。像valgrind 这样的工具会报告分配内存的滥用情况。

【讨论】:

    【解决方案2】:

    Jonathan 的回答解释了这部分代码的问题。

    要修复它,您可以改用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)。关于如何防止这种情况的适当讨论可能超出了这个问题的范围!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 2015-08-09
      相关资源
      最近更新 更多