C에서 Linux 관련 getline() 함수의 예기치 않은 동작

C에서 Linux 관련 getline() 함수의 예기치 않은 동작
#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()) 그 다음 행에는 텍스트 데이터가 손상되었습니다.

관련 정보