【问题标题】:How to malloc for getline implementation如何为 getline 实现 malloc
【发布时间】:2015-05-10 20:01:05
【问题描述】:

我正在尝试将 getline 支持添加到 http-fs-wrapper,但我遇到了一些 malloc 问题。

ssize_t _intercept_getdelim(int fd, char **lineptr, size_t *n, int delim)
{
    intercept_t *obj = intercept[fd];
    int counter;
    size_t nc = sizeof(char);

    counter = -1;
    while (obj->offset < obj->size)
    {
        ++counter;
        if (*lineptr) {
            *lineptr = realloc(*lineptr, (counter + 2) * nc);
        }
        else {
            *lineptr = malloc(nc);
        }
        _intercept_read(fd, lineptr[counter], nc);
        if (*lineptr[counter] == delim)
        {
           break;
        }
    }
    *n = counter ? counter + 1 : counter;
    *lineptr[counter + 2] = '\0';
    // Why do we need a *n when the return value is the same??
    return *n;
}

这里是_intercept_read的相关部分:

size_t _intercept_read(int fd, void *buf, size_t count)
{
    memcpy(buf, obj->ra_buf+bo, count);

当我在 gdb 中逐步执行此操作时,第二次迭代会抛出一个 SIGSEGV(来自 memcpy——它不是结尾 \0,它仍在循环内)。我也不太明白getline/getdelim*n和返回值有什么区别。

【问题讨论】:

  • 不是一个答案,但尝试包装/替换每个 io 函数听起来是实现虚拟 http fs 的一种非常糟糕的方法。只有 open 文件的函数才需要被钩子,它们需要做的就是打开一个管道或本地套接字到一个执行 http 的线程或进程。

标签: c pointers malloc getline


【解决方案1】:

n 和返回值之间的区别在于 n 始终是缓冲区大小,但对于每个 posix 规范的错误状态,返回值可以是 -1。您没有完全处理 EOF(如果它到达 EOF 并且还没有读取任何内容,它应该返回 -1)。

注意,为每个字符重新分配是相当低效的。标准模式是每次需要时将缓冲区大小加倍。这是返回值和 n 可能不同的另一种方式,因为 n 是缓冲区大小,它可能比它返回的读取字符数大得多。

你也不需要特殊情况下一个起始空指针,在这种情况下 realloc 在内部调用 malloc。

buf = realloc(buf...) 是一个不安全的模式,realloc 可以返回 null,你必须将 realloc 结果保存到一个临时变量并在分配之前检查它,否则你会泄漏内存并且可以引用一个空指针.

我认为您在最后添加到缓冲区的尾随 null 实际上没有空间。

【讨论】:

  • 那么问题是第二次迭代的 sigsegv(来自 memcpy)。显然我被指针搞砸了。愿意告诉我在哪里吗?
【解决方案2】:

这行得通:

ssize_t _intercept_getdelim(int fd, char **lineptr, size_t *n, int delim)
{
    intercept_t *obj = intercept[fd];
    int counter = -1;
    char *c, *newbuf;

    *n = 1;
    *lineptr = malloc(*n);
    while (obj->offset < obj->size)
    {
        ++counter;
        if (counter >= *n)
        {
            if ((newbuf = realloc(*lineptr, *n  << 1)))
            {
                *n = *n << 1;
                *lineptr = newbuf;
            }
            else
            {
                return -1;
            }

        }
        c = *lineptr + counter;
        _intercept_read(fd, c, nc);
        if (*c == delim)
        {
           break;
        }
    }
    if (counter > -1)
    {
        *(*lineptr + ++counter) = '\0';
    }
    return counter;
}

【讨论】:

  • 您不需要执行初始 malloc,因为 getdelim 的部分目标是允许重用缓冲区(如果有人尝试这样做,您当前会出现内存泄漏)。但除此之外,这是 realloc 的更清洁用法。您可能希望在返回 -1 之前将 errno 设置为 ENOMEM,但这取决于您对 posix 规范合规性的关心程度。此外,由于您在添加尾随 \0 之前没有检查缓冲区大小,因此仍然可能溢出缓冲区。
猜你喜欢
  • 2013-03-09
  • 2011-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多