fgets함수

dandb3·2023년 6월 4일
0

pwnable

목록 보기
11/22

fgets 함수이다.
이름에서부터 알 수 있듯이, 파일에서 데이터를 get 하는 함수이다.

소스코드는 다음과 같다.

  • _IO_fgets
char *
_IO_fgets (char *buf, int n, FILE *fp)
{
  size_t count;
  char *result;
  int old_error;
  CHECK_FILE (fp, NULL);
  if (n <= 0)
    return NULL;
  if (__glibc_unlikely (n == 1))
    {
      /* Another irregular case: since we have to store a NUL byte and
	 there is only room for exactly one byte, we don't have to
	 read anything.  */
      buf[0] = '\0';
      return buf;
    }
  _IO_acquire_lock (fp);
  /* This is very tricky since a file descriptor may be in the
     non-blocking mode. The error flag doesn't mean much in this
     case. We return an error only when there is a new error. */
  old_error = fp->_flags & _IO_ERR_SEEN;
  fp->_flags &= ~_IO_ERR_SEEN;
  count = _IO_getline (fp, buf, n - 1, '\n', 1);
  /* If we read in some bytes and errno is EAGAIN, that error will
     be reported for next read. */
  if (count == 0 || ((fp->_flags & _IO_ERR_SEEN) && errno != EAGAIN))
    result = NULL;
  else
    {
      buf[count] = '\0';
      result = buf;
    }
  fp->_flags |= old_error;
  _IO_release_lock (fp);
  return result;
}
weak_alias (_IO_fgets, fgets)

함수도 복잡하지 않다.
바로 _IO_getline 함수를 호출하는 것을 알 수 있다. 바로 살펴보자.

  • _IO_getline
size_t
_IO_getline (FILE *fp, char *buf, size_t n, int delim,
	     int extract_delim)
{
  return _IO_getline_info (fp, buf, n, delim, extract_delim, (int *) 0);
}
libc_hidden_def (_IO_getline)
/* Algorithm based on that used by Berkeley pre-4.4 fgets implementation.
   Read chars into buf (of size n), until delim is seen.
   Return number of chars read (at most n).
   Does not put a terminating '\0' in buf.
   If extract_delim < 0, leave delimiter unread.
   If extract_delim > 0, insert delim in output. */
size_t
_IO_getline_info (FILE *fp, char *buf, size_t n, int delim,
		  int extract_delim, int *eof)
{
  char *ptr = buf;
  if (eof != NULL)
    *eof = 0;
  if (__builtin_expect (fp->_mode, -1) == 0)
    _IO_fwide (fp, -1);
  while (n != 0)
    {
      ssize_t len = fp->_IO_read_end - fp->_IO_read_ptr;
      if (len <= 0)
        {
          int c = __uflow (fp);
          if (c == EOF)
            {
              if (eof)
            	*eof = c;
              break;
            }
          if (c == delim)
            {
              if (extract_delim > 0)
            	*ptr++ = c;
              else if (extract_delim < 0)
            	_IO_sputbackc (fp, c);
              if (extract_delim > 0)
            	++len;
              return ptr - buf;
            }
          *ptr++ = c;
          n--;
        }
      else
        {
          char *t;
          if ((size_t) len >= n)
            len = n;
          t = (char *) memchr ((void *) fp->_IO_read_ptr, delim, len);
          if (t != NULL)
            {
              size_t old_len = ptr-buf;
              len = t - fp->_IO_read_ptr;
              if (extract_delim >= 0)
                {
                  ++t;
                  if (extract_delim > 0)
                    ++len;
                }
              memcpy ((void *) ptr, (void *) fp->_IO_read_ptr, len);
              fp->_IO_read_ptr = t;
              return old_len + len;
            }
          memcpy ((void *) ptr, (void *) fp->_IO_read_ptr, len);
          fp->_IO_read_ptr += len;
          ptr += len;
          n -= len;
        }
    }
  return ptr - buf;
}
libc_hidden_def (_IO_getline_info)

만약 len <= 0 이라면 __uflow를 호출하는 것을 알 수 있다.

앞의 fread함수에서의 동작과 비교해 보자.

  • fread 함수
    1. _IO_xsgetn
    2. __underflow
    3. _IO_file_underflow
  • fgets 함수
    1. _IO_fgets
    2. __uflow
    3. _IO_default_uflow
    4. _IO_file_underflow

결국 fread와 같이 _IO_file_underflow를 호출하게 된다. 다만, gets함수이므로 중간에 개행이 나오면 멈춘다는 차이점은 존재한다.

profile
공부 내용 저장소

0개의 댓글