连续使用getline导致segmentation fault

Using getline consecutively causes segmentation fault

我正在尝试使用 getline 从 stdin 读取两行连续的输入。这个最少的代码会导致分段错误,我不确定为什么:

int main() {
    char *ln1 = NULL;
    char *ln2 = NULL;
    size_t lnsz1;
    size_t lnsz2;

    getline(&ln1,&lnsz1,stdin);
    getline(&ln2,&lnsz2,stdin);


}

谁能解释一下我做错了什么?

我在 中说过,将大小设置为零(以及指向空指针的指针)应该可以修复观察到的崩溃。

隐藏在后台的是一个假设,即导致崩溃的 getline() 的具体实施有些错误。它可能出错的一种可能方式是,如果它在分配 space 时使用大小参数,因为指针为空。这有点不太可能,但问题没有提供有关哪个平台导致崩溃的信息。

getline() 的 POSIX 规范说:

ssize_t getline(char **restrict lineptr, size_t *restrict n, FILE *restrict stream);

The application shall ensure that *lineptr is a valid argument that could be passed to the free() function. If *n is non-zero, the application shall ensure that *lineptr either points to an object of size at least *n bytes, or is a null pointer.

If *lineptr is a null pointer or if the object pointed to by *lineptr is of insufficient size, an object shall be allocated as if by malloc() or the object shall be reallocated as if by realloc(), respectively, such that the object is large enough to hold the characters to be written to it, including the terminating NUL, and *n shall be set to the new size. If the object was allocated, or if the reallocation operation moved the object, *lineptr shall be updated to point to the new object or new location.

Upon successful completion, the getline() and getdelim() functions shall return the number of bytes written into the buffer, including the delimiter character if one was encountered before EOF, but excluding the terminating NUL character. If the end-of-file indicator for the stream is set, or if no characters were read and the stream is at end-of-file, the end-of-file indicator for the stream shall be set and the function shall return -1. If an error occurs, the error indicator for the stream shall be set, and the function shall return -1 and set errno to indicate the error.

问题中的代码没有self-evidently滥用这些规则。应用程序确保 *lineptr 是一个空指针——这是一个可以传递给 free() 的值。 *n 的值是多少并不重要,因为 *lineptr 是一个空指针。

一种实验方法是尝试打印未初始化变量(lnsz1lnsz2)中的值,但这种实验可以说是调用了未定义的行为。另一种方法是将变量初始化为一些较大的值——例如 SIZE_MAXSIZE_MAX / 2(其中 SIZE_MAX 在 C11 <stdint.h> 中定义,但在早期版本的 C 标准中没有定义)或其他类似的膨胀值。当然,您还应该使用 0 的值进行测试,并且可以使用其他较小的值(例如 1816 等进行一些测试。所有这些测试将在指针设置为空指针的情况下进行。如果您可以使用内存分配包来调用 malloc()(或 realloc())的调试版本,您可能能够记录请求的内存大小。如果在第二次调用时发生崩溃,您可能会在第一次调用 getline() 后打印 lnsz1 的值获得一些信息。

不过,这样的调查几乎不值得付出努力。将指针和大小都设置为零应该可以解决问题。如果没有,则需要进行更多调查。然而,这不太可能是问题所在。

//#define _XOPEN_SOURCE 700 // Explicitly request POSIX support
#include <stdio.h>

int main(void)
{
    char *ln1 = NULL;
    char *ln2 = NULL;
    size_t lnsz1 = 0;
    size_t lnsz2 = 0;
    ssize_t len1 = -1;
    ssize_t len2 = -1;

    if ((len1 = getline(&ln1, &lnsz1, stdin)) != -1)
    {
        printf("%zd (%zu: %p) [%s]\n", len1, lnsz1, (void *)ln1, ln1);
        if ((len2 = getline(&ln2, &lnsz2, stdin)) != -1)
            printf("%zd (%zu: %p) [%s]\n", len2, lnsz2, (void *)ln2, ln2);
    }
    free(ln1);
    free(ln2);

    return 0;
}

请注意 getline() 特别是 return 和 -1 而不是 EOF 当它检测到错误或 end-of-file 时。在大多数系统上,这两个值是相同的,但是 C standard 只要求 EOF 是负数——它不要求它是 -1。我无法确定 0 的 return 值对 getline().

有效的任何情况