valgrind条件跳转或移动取决于未初始化的值

时间:2013-07-14 15:39:06

标签: c debugging valgrind

我有以下代码,通过填充0作为前缀将IP地址修复为15位。

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

char *function(char *newhost){
     char *IPaddr;
     IPaddr = (char *)calloc(16, sizeof(char));

    size_t i=0 , j= 0;
    for(i=0, j=0; j<15; i++, j++){
        if((newhost[strlen(newhost)-(i+1)] == '.')){   //////////line 11
            if( j == 3 || j == 7 || j == 11){
                IPaddr[14-j] = '.';
            }else if(j<3){
                while(!(j==3)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }else if(j > 3 && j<7){
                while(!(j==7)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }else if(j>7 && j<11){
                while(!(j==11)){
                    IPaddr[14-j]='0';
                    j++;
                }
                IPaddr[14-j] = '.';
            }
        }else if(newhost[strlen(newhost)-(i+1)] == '\0'){ ///////////line33
            while(!(j==15)){
                IPaddr[14-j] = '0';
                j++;
               }
        }else{
            IPaddr[14-j] = newhost[strlen(newhost)-(i+1)];
        }
    }
    printf("IPaddr: %s\n", IPaddr);
    return IPaddr;

}


int main(int argc,char *argv[]){  /////////line48
    char host[100] = {'\0'};
    strcpy(host, "10.0.0.2");
    char *new_IP;
    new_IP = function(host);  ////////////line52
    printf("newIP:%s\n",new_IP);
    free(new_IP);

return 0;
}

代码工作,编译器既不输出错误也不输出警告。但是,valgrind输出(valgrind --tool = memcheck --leak-check = yes --track-originins = yes test )

==22544== Conditional jump or move depends on uninitialised value(s)
==22544==    at 0x8048547: function (test.c:11)
==22544==    by 0x804872B: main (test.c:52)
==22544==  Uninitialised value was created by a stack allocation
==22544==    at 0x80486DB: main (test.c:48)
==22544== 
==22544== Conditional jump or move depends on uninitialised value(s)
==22544==    at 0x8048654: function (test.c:33)
==22544==    by 0x804872B: main (test.c:52)
==22544==  Uninitialised value was created by a stack allocation
==22544==    at 0x80486DB: main (test.c:48)

有谁能告诉我如何修复代码?

1 个答案:

答案 0 :(得分:5)

麻烦的是,在函数中,你正在做:

for (i=0, j=0; j < 15; i++, j++){
    if ((newhost[strlen(newhost)-(i+1)] == '.')){  

当你经历循环时,i变得大于初始化字符串的长度,但我希望生成'越界'错误。但是,由于main()中的变量未动态分配,因此valgrind可能无法提供帮助。我建议将main()修改为:

int main(int argc, char *argv[])
{
    char *host = malloc(100);
    if (host != 0)
    {
        strcpy(host, "10.0.0.2");
        char *new_IP = function(host);
        printf("newIP:%s\n", new_IP);
        free(host);
        free(new_IP);
    }
    return 0;
}

我希望valgrind抱怨更多问题,尤其是超出内存访问权限。

单独:

  • 由于strlen(newhost)在函数运行时没有改变,所以你应该在循环之外计算一次。
  • 我不确定你为什么使用if ((...))符号。如果这是一个反射动作,以避免编译器警告在条件中使用赋值,那么你就失去了警告的目的。
  • 使用sscanf()将字符串解析为4个数字会更容易,然后使用sprintf()对其进行格式化吗?

    char *function(const char *newhost)
    {
        int o1, o2, o3, o4;
        char *result = 0;
        if (sscanf(newhost, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) == 4)
        {
            /* Should check that values are in range 0..255 */
            result = malloc(16);
            if (result != 0)
                sprintf(result, "%.3d.%.3d.%.3d.%.3d", o1, o2, o3, o4);
        }
        return result;
    }
    

function()的另一种替代实现,仅使用字符串复制:

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

char *function(const char *newhost)
{
    char *result = malloc(16);
    if (result != 0)
    {
        strcpy(result, "000.000.000.000");
        const char *beg = newhost;

        for (int i = 0; i < 4; i++)
        {
            const char *end = strchr(beg, '.');
            if (end == 0)
                end = beg + strlen(beg);
            memcpy(result + (i * 4) + 3 - (end - beg), beg, end - beg);
            beg = end + 1;
        }
    }
    return result;
}

int main(void)
{
    char host[] = "10.0.0.2";
    char *newhost = function(host);
    printf("%s => %s\n", host, newhost);
    free(newhost);
    return 0;
}

计算每个段中的位数,然后将其复制到结果缓冲区中的正确位置,该缓冲区已在正确的位置填充了零和点。它避免了所有像3,7,11那样乱丢原始代码的神奇数字。

我还建议使用不同的接口来实现功能,避免动态内存分配:

void function(const char *oldhost, char *newhost)

我们可以讨论void vs int,但是调用函数应该提供要写入输出的(已知的,固定大小)缓冲区,以避免必须做动态内存分配。如果函数对给定的字符串进行任何验证,则使用int;否则,它可以是void。如果传递了错误的IP地址,现有代码通常不报告错误。