![C에서 Linux 관련 getline() 함수의 예기치 않은 동작](https://linux55.com/image/213299/C%EC%97%90%EC%84%9C%20Linux%20%EA%B4%80%EB%A0%A8%20getline()%20%ED%95%A8%EC%88%98%EC%9D%98%20%EC%98%88%EA%B8%B0%EC%B9%98%20%EC%95%8A%EC%9D%80%20%EB%8F%99%EC%9E%91.png)
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1024
void reverse(FILE *, FILE *);
int main(int argc, char ** argv)
{
...
reverse(fptr, stdout);
...
return 0;
}
void reverse(FILE * instream, FILE * outstream)
{
char ** buf;
char * lbuf;
int counter, i;
size_t slen;
counter = 0;
buf = malloc(MAXLEN * sizeof(char));
if (buf == NULL)
{
fputs("malloc failed\n", stderr);
exit(EXIT_FAILURE);
}
lbuf = NULL;
while ((counter < MAXLEN) && (getline(&lbuf, &slen, instream) != -1))
{
buf[counter] = lbuf;
counter++;
lbuf = NULL;
}
for (i = counter - 1; i >= 0; i--)
{
fputs(buf[i], outstream);
free(buf[i]);
}
free(buf);
}
나는 파일을 역순으로 인쇄하기 위해 이 함수를 작성했습니다.
Hello World
How are you ?
what are you doing ?
출력은 다음과 같아야합니다
what are you doing ?
How are you ?
Hello World
그런데 예상치 못한 동작이 발생했습니다. 나는 임의로 긴 줄을 스캔하기 위해 Linux 특정 stdio
기능을 사용하고 있습니다. getline()
문제는 값이 4, 5, 6, ...이면 MAXLEN
출력을 인쇄할 때 프로그램이 double free or corrupt address error abort()
특정 기능을 제공한다는 것입니다.free()
함수가 반환한 주소를 살펴본 결과 geline()
4번의 반복 후에 함수가 반환한 첫 번째 버퍼의 주소가 getline()
손상된 것 같습니다. 2 또는 충분히 큰 경우 MAXLEN
(예: 1024) 문제가 없습니다.
입력 샘플내가 가져 갔어
When to the sessions of sweet silent thought
I summon up remembrance of things past,
I sigh the lack of many a thing I sought,
And with old woes new wail my dear time's waste:
Then can I drown an eye, unused to flow,
For precious friends hid in death's dateless night
And weep afresh love's long since cancell's woe,
답변1
에서 char ** buf;
유형은 공간을 할당하는 배열 buf
입니다 .pointer to char*
char*
buf = malloc(MAXLEN * sizeof(char));
이는 MAXLEN 포인터(64비트 CPU에서 각각 8바이트)가 아닌 MAXLEN 문자에만 공간을 할당합니다. 따라서 나중에 할당된 공간을 초과하고 항목이 손상됩니다(겹침 buf[counter]
).
올바른 할당은 다음과 같습니다.buf = malloc (MAXLEN * sizeof(char *));
일반적으로 나는 반환된 포인터의 유형에 따라 할당하는 것을 선호합니다.
buf = malloc (MAXLEN * sizeof(*buf));
즉, " buf
사물이 가리키는 MAXLEN 항목에 대한 공간을 할당합니다." 이렇게 하면 buf
유형을 변경할 때 발생하는 오류를 방지할 수 있습니다.
getline()
문제의 일부는 아닙니다. 반환되는 포인터를 너무 작은 배열에 저장하기만 하면 됩니다. 코드가 작은 데이터 세트에 대해 작동하는 이유는 malloc()
객체 정렬을 유지하기 위해 할당이 16바이트 또는 32바이트로 반올림되기 때문입니다. 둘 다 자체 사용 가능 목록에 반대되므로 컴파일러는 사용자 구조 가정 정렬에 대해 합리적인 결정을 내릴 수 있습니다.
따라서 (일반적으로) 데이터의 처음 두 행은 괜찮고, 다음 두 행에는 다음 행의 숨겨진 헤더가 손상되었으며(broken free()
) 그 다음 행에는 텍스트 데이터가 손상되었습니다.