0
gcc (GCC) 4.7.2
valgrind-3.8.1
c89

你好,

==1160== Invalid read of size 1
==1160==    at 0x8048C94: get_input_values (parse_cmd_input.c:278)
==1160==    by 0x8048BA0: parse_input (parse_cmd_input.c:245)
==1160==    by 0x80489A1: main (parse_cmd_input.c:50)
==1160==  Address 0x40ef02c is 0 bytes after a block of size 4 alloc'd
==1160==    at 0x40072C5: calloc (vg_replace_malloc.c:593)
==1160==    by 0x8048B28: parse_input (parse_cmd_input.c:239)
==1160==    by 0x80489A1: main (parse_cmd_input.c:50)

所以它说地址正在读取分配大小为 4 的零字节,并试图从中读取 1 个字节。但是,我没有超出数组的边界,我正在访问元素 0。

我用 gdb 检查过,元素零包含一个字符。

我的程序没有崩溃,而且似乎工作正常。但这可能会导致生产服务器出现问题。

我不确定我在这里是否正确:应该是:

cpy_input = calloc(strlen(input) + 1, sizeof(char*));

或者:

cpy_input = calloc(strlen(input) + 1, sizeof(char));

在我的系统上,一个 char 是 1 个字节,指向 char 的指针是 4 个字节。

传入的字符串将是这样的"25 b"

int parse_input(const char *input)
{
    char *cpy_input = NULL;
    int has_error = -1;

    if(strlen(input) == 0) {
        LOG_ERR("FAILED: Empty string");
        return -1;
    }

    cpy_input = calloc(strlen(input) + 1, sizeof(char));

    apr_cpystrn(cpy_input, input, sizeof(cpy_input));
    LOG_INFO("[ %s ]", cpy_input);

    memset(&channel, 0, sizeof channel);
    has_error = get_input_values(cpy_input, &channel);

    free(cpy_input);

    return has_error;
}


int get_input_values(const char *str, channel_t *channel)
{
    size_t i = 0;
    size_t k = 0;
    int upper_flag = 0;

    /* Indicates no digits or command found*/
    channel->lower = -1;
    channel->upper = -1;
    channel->cmd = -1;

#define DIG_BUFFER_SIZE 32
    char dig_buffer_lower[DIG_BUFFER_SIZE];
    char dig_buffer_upper[DIG_BUFFER_SIZE];

    if(strlen(str) == 0) {
        LOG_ERR("FAILED: Empty string");
        return -1;
    }

    memset(dig_buffer_lower, 0, DIG_BUFFER_SIZE);
    memset(dig_buffer_upper, 0, DIG_BUFFER_SIZE);

    LOG_INFO("SIZE %d %d", sizeof(char), sizeof(char*));

    /* Increament and check for digits */
    for(i = 0; i < DIG_BUFFER_SIZE; i++) {
    switch(str[i]) {
        case 32: /* ignore space */
            continue;

        case 45: /* '-' Start upper bounds */
            LOG_DEBUG("Found a '-' check upper value");
            /* Having a second '-' means the string is invalid */
            if(!upper_flag) {
                upper_flag = 1;
                k = 0;
            }
            break;

        } /* switch */

        /* Insert on digits into the lower and upper values */
    if(isdigit(str[i])) {
            if(upper_flag) {
                dig_buffer_upper[k++] = str[i];
                LOG_DEBUG("dig_buffer_upper[%d] %s", i, dig_buffer_upper);
            }
            else {
                /* Add to digit buffer */
                dig_buffer_lower[k++] = str[i];
                LOG_DEBUG("dig_buffer_lower[%d] %s", i, dig_buffer_lower);
            }
        }
    } /* for loop */

非常感谢您的任何建议,

4

2 回答 2

4

sizeof(cpy_input)只是sizeof(char *),而不是字符串长度。相反,说:

apr_cpystrn(cpy_input, input, strlen(input) + 1);

或者更好的是,使用赤裸的strcpy或等效的。也没有必要用 将数组清零calloc,因为无论如何您都将要覆盖它。由于sizeof(char)1根据定义,您可以使用以下方式分配数组:

cpy_input = malloc(strlen(input) + 1);

(想想字符串一分钟:你已经在一个合理的地方有一个空终止符的摆布,或者strlen会崩溃或返回一个巨大的值。一旦你相信 的结果strlen,你就可以保证分配足够的内存给strcpy字符串和空终止符。或者,您可以使用memcpy可能更有效的副本,因为您知道大小。)

于 2013-07-04T07:39:04.460 回答
1

好的,也许我遗漏了一些东西,但是您的循环for将遍历0 .. DIG_BUFFER_SIZE-1. str[i]我看不出是什么导致该循环提前中断,特别是因为它似乎立即包装 a switch,因此任何break内部的switch都会退出switch,但不会退出for.

calloc(strlen(input) + 1, sizeof(char));正确地为输入的确切长度分配存储。get_input_values如果字符串短于DIG_BUFFER_SIZE.

(我很想被证明是错误的,但要知道,我们需要查看更多代码。)

于 2013-07-04T07:42:37.297 回答