IO-源码阅读 glibc 2.35

文章目录

参考

https://wiki.wgpsec.org/knowledge/ctf/iofile.html
https://blog.wingszeng.top/pwn-glibc-file-struct-and-related-functions/#读取缓冲区

缓存机制

  • 读:先从文件读取大部分数据到缓冲区,再从缓冲区读取需要的部分数据
  • 写:先写到缓冲区,等缓冲区满了之后再写到文件

IO_FILE_PLUS

fopen

fopen就是IO_new_fopen,首先会进入fopen_internal

fopen_internal

c 复制代码
FILE *
__fopen_internal (const char *filename, const char *mode, int is32)
{
  struct locked_FILE
  {
    struct _IO_FILE_plus fp;
#ifdef _IO_MTSAFE_IO
    _IO_lock_t lock;
#endif
    struct _IO_wide_data wd;
  } *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));

  if (new_f == NULL)
    return NULL;
#ifdef _IO_MTSAFE_IO
  new_f->fp.file._lock = &new_f->lock;
#endif
  _IO_no_init (&new_f->fp.file, 0, 0, &new_f->wd, &_IO_wfile_jumps);
  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
  _IO_new_file_init_internal (&new_f->fp);
  if (_IO_file_fopen ((FILE *) new_f, filename, mode, is32) != NULL)
    return __fopen_maybe_mmap (&new_f->fp.file);

  _IO_un_link (&new_f->fp);
  free (new_f);
  return NULL;
}

会分配sizeof (struct locked_FILE)大小的结构体,然后_IO_no_init 初始化分配的结构体,_IO_JUMPS 对vatable赋值,_IO_new_file_init_internal 对结构体链接到list_all中,然后_IO_file_fopen 会系统调用打开文件并设置文件描述符

_IO_no_init

c 复制代码
560     void
561     _IO_no_init (FILE *fp, int flags, int orientation,
562                  struct _IO_wide_data *wd, const struct _IO_jump_t *jmp)
563     {
564       _IO_old_init (fp, flags);
565       fp->_mode = orientation;
566       if (orientation >= 0)
567         {
568           fp->_wide_data = wd;
569           fp->_wide_data->_IO_buf_base = NULL;
570           fp->_wide_data->_IO_buf_end = NULL;
571           fp->_wide_data->_IO_read_base = NULL;
572           fp->_wide_data->_IO_read_ptr = NULL;
573           fp->_wide_data->_IO_read_end = NULL;
574           fp->_wide_data->_IO_write_base = NULL;
575           fp->_wide_data->_IO_write_ptr = NULL;
576           fp->_wide_data->_IO_write_end = NULL;
577           fp->_wide_data->_IO_save_base = NULL;
578           fp->_wide_data->_IO_backup_base = NULL;
579           fp->_wide_data->_IO_save_end = NULL;
580
581           fp->_wide_data->_wide_vtable = jmp;
582         }
583       else
584         /* Cause predictable crash when a wide function is called on a byte
585            stream.  */
586         fp->_wide_data = (struct _IO_wide_data *) -1L;
587       fp->_freeres_list = NULL;
588     }

_IO_old_init

c 复制代码
8
529     void
530     _IO_old_init (FILE *fp, int flags)
531     {
532       fp->_flags = _IO_MAGIC|flags;
533       fp->_flags2 = 0;
534       if (stdio_needs_locking)
535         fp->_flags2 |= _IO_FLAGS2_NEED_LOCK;
536       fp->_IO_buf_base = NULL;
537       fp->_IO_buf_end = NULL;
538       fp->_IO_read_base = NULL;
539       fp->_IO_read_ptr = NULL;
540       fp->_IO_read_end = NULL;
541       fp->_IO_write_base = NULL;
542       fp->_IO_write_ptr = NULL;
543       fp->_IO_write_end = NULL;
544       fp->_chain = NULL; /* Not necessary. */
545
546       fp->_IO_save_base = NULL;
547       fp->_IO_backup_base = NULL;
548       fp->_IO_save_end = NULL;
549       fp->_markers = NULL;
550       fp->_cur_column = 0;
551     #if _IO_JUMPS_OFFSET
552       fp->_vtable_offset = 0;
553     #endif
554     #ifdef _IO_MTSAFE_IO
555       if (fp->_lock != NULL)
556         _IO_lock_init (*fp->_lock);
557     #endif
558     }

_IO_new_file_init_internal

c 复制代码
void
105     _IO_new_file_init_internal (struct _IO_FILE_plus *fp)
106     {
107       /* POSIX.1 allows another file handle to be used to change the position
108          of our file descriptor.  Hence we actually don't know the actual
109          position before we do the first fseek (and until a following fflush). */
110       fp->file._offset = _IO_pos_BAD;
111       fp->file._flags |= CLOSED_FILEBUF_FLAGS;
112
113       _IO_link_in (fp);
114       fp->file._fileno = -1;
115     }
c 复制代码
      void
86      _IO_link_in (struct _IO_FILE_plus *fp)
87      {
88        if ((fp->file._flags & _IO_LINKED) == 0)
89          {
90            fp->file._flags |= _IO_LINKED;
91      #ifdef _IO_MTSAFE_IO
92            _IO_cleanup_region_start_noarg (flush_cleanup);
93            _IO_lock_lock (list_all_lock);
94            run_fp = (FILE *) fp;
95            _IO_flockfile ((FILE *) fp);
96      #endif
97            fp->file._chain = (FILE *) _IO_list_all;
98            _IO_list_all = fp;
99      #ifdef _IO_MTSAFE_IO
100           _IO_funlockfile ((FILE *) fp);
101           run_fp = NULL;
102           _IO_lock_unlock (list_all_lock);
103           _IO_cleanup_region_end (0);
104     #endif
105         }
106     }
107     libc_hidden_def (_IO_link_in)

_IO_new_file_fopen

c 复制代码
 FILE *
211     _IO_new_file_fopen (FILE *fp, const char *filename, const char *mode,
212                         int is32not64)
213     {
214       int oflags = 0, omode;
215       int read_write;
216       int oprot = 0666;
217       int i;
218       FILE *result;
219       const char *cs;
220       const char *last_recognized;
221
222       if (_IO_file_is_open (fp))
223         return 0;
224       switch (*mode)
225         {
226         case 'r':
227           omode = O_RDONLY;
228           read_write = _IO_NO_WRITES;
229           break;
230         case 'w':
231           omode = O_WRONLY;
232           oflags = O_CREAT|O_TRUNC;
233           read_write = _IO_NO_READS;
234           break;
235         case 'a':
236           omode = O_WRONLY;
237           oflags = O_CREAT|O_APPEND;
238           read_write = _IO_NO_READS|_IO_IS_APPENDING;
239           break;
240         default:
241           __set_errno (EINVAL);
242           return NULL;
243         }
244       last_recognized = mode;
245       for (i = 1; i < 7; ++i)
246         {
247           switch (*++mode)
248             {
249             case '\0':
250               break;
251             case '+':
252               omode = O_RDWR;
253               read_write &= _IO_IS_APPENDING;
254               last_recognized = mode;
255               continue;
256             case 'x':
257               oflags |= O_EXCL;
258               last_recognized = mode;
259               continue;
260             case 'b':
261               last_recognized = mode;
262               continue;
pwndbg> 
263             case 'm':
264               fp->_flags2 |= _IO_FLAGS2_MMAP;
265               continue;
266             case 'c':
267               fp->_flags2 |= _IO_FLAGS2_NOTCANCEL;
268               continue;
269             case 'e':
270               oflags |= O_CLOEXEC;
271               fp->_flags2 |= _IO_FLAGS2_CLOEXEC;
272               continue;
273             default:
274               /* Ignore.  */
275               continue;
276             }
277           break;
278         }
279
280       result = _IO_file_open (fp, filename, omode|oflags, oprot, read_write,
281                               is32not64);
282
283       if (result != NULL)
284         {
285           /* Test whether the mode string specifies the conversion.  */
286           cs = strstr (last_recognized + 1, ",ccs=");
287           if (cs != NULL)
288             {
289               /* Yep.  Load the appropriate conversions and set the orientation
290                  to wide.  */
291               struct gconv_fcts fcts;
292               struct _IO_codecvt *cc;
293               char *endp = __strchrnul (cs + 5, ',');
294               char *ccs = malloc (endp - (cs + 5) + 3);
295
296               if (ccs == NULL)
297                 {
298                   int malloc_err = errno;  /* Whatever malloc failed with.  */
299                   (void) _IO_file_close_it (fp);
300                   __set_errno (malloc_err);
301                   return NULL;
302                 }
303
304               *((char *) __mempcpy (ccs, cs + 5, endp - (cs + 5))) = '\0';
305               strip (ccs, ccs);
306
307               if (__wcsmbs_named_conv (&fcts, ccs[2] == '\0'
308                                        ? upstr (ccs, cs + 5) : ccs) != 0)
309                 {
310                   /* Something went wrong, we cannot load the conversion modules.
311                      This means we cannot proceed since the user explicitly asked
312                      for these.  */
313                   (void) _IO_file_close_it (fp);
314                   free (ccs);
315                   __set_errno (EINVAL);
316                   return NULL;
317                 }
318
319               free (ccs);
320
321               assert (fcts.towc_nsteps == 1);
322               assert (fcts.tomb_nsteps == 1);
323
324               fp->_wide_data->_IO_read_ptr = fp->_wide_data->_IO_read_end;
325               fp->_wide_data->_IO_write_ptr = fp->_wide_data->_IO_write_base;
326
327               /* Clear the state.  We start all over again.  */
328               memset (&fp->_wide_data->_IO_state, '\0', sizeof (__mbstate_t));
329               memset (&fp->_wide_data->_IO_last_state, '\0', sizeof (__mbstate_t));
330
331               cc = fp->_codecvt = &fp->_wide_data->_codecvt;
332
333               cc->__cd_in.step = fcts.towc;
334
335               cc->__cd_in.step_data.__invocation_counter = 0;
336               cc->__cd_in.step_data.__internal_use = 1;
337               cc->__cd_in.step_data.__flags = __GCONV_IS_LAST;
338               cc->__cd_in.step_data.__statep = &result->_wide_data->_IO_state;
339
340               cc->__cd_out.step = fcts.tomb;
341
342               cc->__cd_out.step_data.__invocation_counter = 0;
343               cc->__cd_out.step_data.__internal_use = 1;
344               cc->__cd_out.step_data.__flags = __GCONV_IS_LAST | __GCONV_TRANSLIT;
345               cc->__cd_out.step_data.__statep = &result->_wide_data->_IO_state;
346
347               /* From now on use the wide character callback functions.  */
348               _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
349
350               /* Set the mode now.  */
351               result->_mode = 1;
352             }
353         }
354
355       return result;
356     }
357     libc_hidden_ver (_IO_new_file_fopen, _IO_file_fopen)

_IO_file_open

c 复制代码
    FILE *
180     _IO_file_open (FILE *fp, const char *filename, int posix_mode, int prot,
181                    int read_write, int is32not64)
182     {
183       int fdesc;
184       if (__glibc_unlikely (fp->_flags2 & _IO_FLAGS2_NOTCANCEL))
185         fdesc = __open_nocancel (filename,
186                                  posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
187       else
188         fdesc = __open (filename, posix_mode | (is32not64 ? 0 : O_LARGEFILE), prot);
189       if (fdesc < 0)
190         return NULL;
191       fp->_fileno = fdesc;
192       _IO_mask_flags (fp, read_write,_IO_NO_READS+_IO_NO_WRITES+_IO_IS_APPENDING);
193       /* For append mode, send the file offset to the end of the file.  Don't
194          update the offset cache though, since the file handle is not active.  */
195       if ((read_write & (_IO_IS_APPENDING | _IO_NO_READS))
196           == (_IO_IS_APPENDING | _IO_NO_READS))
197         {
198           off64_t new_pos = _IO_SYSSEEK (fp, 0, _IO_seek_end);
199           if (new_pos == _IO_pos_BAD && errno != ESPIPE)
200             {
201               __close_nocancel (fdesc);
202               return NULL;
203             }
204         }
205       _IO_link_in ((struct _IO_FILE_plus *) fp);
206       return fp;
207     }
208     libc_hidden_def (_IO_file_open)

fread

fread实际调用_IO_fread

_IO_fread

buf是要读取后保存到的位置,fp是要读取的文件

会调用_IO_sgetn 函数

c 复制代码
30      size_t  _IO_fread (void *buf, size_t size, size_t count, FILE *fp)
31      {
32        size_t bytes_requested = size * count;
33        size_t bytes_read;
34        CHECK_FILE (fp, 0);
35        if (bytes_requested == 0)
36          return 0;
37        _IO_acquire_lock (fp);
38        bytes_read = _IO_sgetn (fp, (char *) buf, bytes_requested);
39        _IO_release_lock (fp);
40        return bytes_requested == bytes_read ? count : bytes_read / size;
41      }
42      libc_hidden_def (_IO_fread)

_IO_sgetn

c 复制代码
   407 size_t
   408 _IO_sgetn (FILE *fp, void *data, size_t n)
   409 {
   410   /* FIXME handle putback buffer here! */
 ► 411   return _IO_XSGETN (fp, data, n);
   412 }
   413 libc_hidden_def (_IO_sgetn)

_IO_XSGETN (fp, data, n)会调用到_IO_file_xsgetn 函数

c 复制代码
1270    size_t
1271    _IO_file_xsgetn (FILE *fp, void *data, size_t n)
1272    {
1273      size_t want, have;
1274      ssize_t count;
1275      char *s = data;
1276
1277      want = n;
1278
1279      if (fp->_IO_buf_base == NULL)
1280        {
1281          /* Maybe we already have a push back pointer.  */
1282          if (fp->_IO_save_base != NULL)
1283            {
1284              free (fp->_IO_save_base);
1285              fp->_flags &= ~_IO_IN_BACKUP;
1286            }
1287          _IO_doallocbuf (fp);
1288        }
1289
1290      while (want > 0)
1291        {
1292          have = fp->_IO_read_end - fp->_IO_read_ptr;
1293          if (want <= have)
1294            {
1295              memcpy (s, fp->_IO_read_ptr, want);
1296              fp->_IO_read_ptr += want;
1297              want = 0;
1298            }
1299          else
1300            {
1301              if (have > 0)
1302                {
1303                  s = __mempcpy (s, fp->_IO_read_ptr, have);
1304                  want -= have;
1305                  fp->_IO_read_ptr += have;
1306                }
1307
1308              /* Check for backup and repeat */
1309              if (_IO_in_backup (fp))
1310                {
1311                  _IO_switch_to_main_get_area (fp);
1312                  continue;
1313                }
1314
1315              /* If we now want less than a buffer, underflow and repeat
1316                 the copy.  Otherwise, _IO_SYSREAD directly to
1317                 the user buffer. */
1318              if (fp->_IO_buf_base
1319                  && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base))
1320                {
1321                  if (__underflow (fp) == EOF)
1322                    break;
pwndbg> 
1323
1324                  continue;
1325                }
1326
1327              /* These must be set before the sysread as we might longjmp out
1328                 waiting for input. */
1329              _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
1330              _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);
1331
1332              /* Try to maintain alignment: read a whole number of blocks.  */
1333              count = want;
1334              if (fp->_IO_buf_base)
1335                {
1336                  size_t block_size = fp->_IO_buf_end - fp->_IO_buf_base;
1337                  if (block_size >= 128)
1338                    count -= want % block_size;
1339                }
1340
1341              count = _IO_SYSREAD (fp, s, count);
1342              if (count <= 0)
1343                {
1344                  if (count == 0)
1345                    fp->_flags |= _IO_EOF_SEEN;
1346                  else
1347                    fp->_flags |= _IO_ERR_SEEN;
1348
1349                  break;
1350                }
1351
1352              s += count;
1353              want -= count;
1354              if (fp->_offset != _IO_pos_BAD)
1355                _IO_pos_adjust (fp->_offset, count);
1356            }
1357        }
1358
1359      return n - want;
1360    }
1361    libc_hidden_def (_IO_file_xsgetn)

首先判断缓冲区是否初始化,没有初始化会调用_IO_doallocbuf 申请一块区域作为缓冲区,然后判断输入缓冲区剩余的能否满足要读出去的,满足的话__mempcpy ,如果只是输入缓冲的内容小于用户要读的长度会想输入缓冲内容memcpy ,然后调用调用__underflow。如果直接没有输入缓冲可以给用户的,也会调用__underflow来填充缓冲区,然后某些情况fp->_IO_buf_base 1319 && want < (size_t) (fp->_IO_buf_end - fp->_IO_buf_base)为false会使用系统级别读取。直接从文件读取到用户那里_IO_SYSREAD (fp, s, count);

_IO_doallocbuf

c 复制代码
341     void
342     _IO_doallocbuf (FILE *fp)
343     {
344       if (fp->_IO_buf_base)
345         return;
346       if (!(fp->_flags & _IO_UNBUFFERED) || fp->_mode > 0)
347         if (_IO_DOALLOCATE (fp) != EOF)
348           return;
349       _IO_setb (fp, fp->_shortbuf, fp->_shortbuf+1, 0);
350     }
351     libc_hidden_def (_IO_doallocbuf)

_IO_DOALLOCATE (fp)调用_IO_file_doallocate

_IO_file_doallocate

c 复制代码
76      int
77      _IO_file_doallocate (FILE *fp)
78      {
79        size_t size;
80        char *p;
81        struct __stat64_t64 st;
82
83        size = BUFSIZ;
84        if (fp->_fileno >= 0 && __builtin_expect (_IO_SYSSTAT (fp, &st), 0) >= 0)
85          {
86            if (S_ISCHR (st.st_mode))
87              {
88                /* Possibly a tty.  */
89                if (
90      #ifdef DEV_TTY_P
91                    DEV_TTY_P (&st) ||
92      #endif
93                    local_isatty (fp->_fileno))
94                  fp->_flags |= _IO_LINE_BUF;
95              }
96      #if defined _STATBUF_ST_BLKSIZE
97            if (st.st_blksize > 0 && st.st_blksize < BUFSIZ)
98              size = st.st_blksize;
99      #endif
100         }
101       p = malloc (size);
102       if (__glibc_unlikely (p == NULL))
103         return EOF;
104       _IO_setb (fp, p, p + size, 1);
105       return 1;
106     }
107     libc_hidden_def (_IO_file_doallocate)

_IO_SYSSTAT去获取文件信息,_IO_SYSSTAT函数是vtable中的__stat函数。获取文件信息,修改相应需要malloc申请的size。然后调用_IO_setb设置_IO_buf_base和_IO_buf_end为malloc申请的起始地址和结束地址

_IO_file_stat

_IO_SYSSTAT 会调用_IO_file_stat

c 复制代码
1144    int
1145    _IO_file_stat (FILE *fp, void *st)
1146    {
1147      return __fstat64_time64 (fp->_fileno, (struct __stat64_t64 *) st);
1148    }
1149    libc_hidden_def (_IO_file_stat)

然后调用__fstat64_time64

c 复制代码
      int
28      __fstat64_time64 (int fd, struct __stat64_t64 *buf)
29      {
30        if (fd < 0)
31          {
32            __set_errno (EBADF);
33            return -1;
34          }
35        return __fstatat64_time64 (fd, "", buf, AT_EMPTY_PATH);
36      }
37      #if __TIMESIZE != 64
38      hidden_def (__fstat64_time64)

然后调用__fstatat64_time64

c 复制代码
150     int
151     __fstatat64_time64 (int fd, const char *file, struct __stat64_t64 *buf,
152                         int flag)
153     {
154       int r;
155
156     #if FSTATAT_USE_STATX
157       r = fstatat64_time64_statx (fd, file, buf, flag);
158     # ifndef __ASSUME_STATX
159       if (r == -ENOSYS)
160         r = fstatat64_time64_stat (fd, file, buf, flag);
161     # endif
162     #else
163       r = fstatat64_time64_stat (fd, file, buf, flag);
164     #endif
165
166       return INTERNAL_SYSCALL_ERROR_P (r)
167              ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
168              : 0;
169     }
170     #if __TIMESIZE != 64
171     hidden_def (__fstatat64_time64)

调用fstatat64_time64_stat

c 复制代码
 static inline int
89      fstatat64_time64_stat (int fd, const char *file, struct __stat64_t64 *buf,
90                             int flag)
91      {
92        int r;
93
94      #if XSTAT_IS_XSTAT64
95      # ifdef __NR_newfstatat
96        /* 64-bit kABI, e.g. aarch64, ia64, powerpc64*, s390x, riscv64, and
97           x86_64.  */
98        r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, buf, flag);
99      # elif defined __NR_fstatat64
100     #  if STAT64_IS_KERNEL_STAT64
101       /* 64-bit kABI outlier, e.g. alpha  */
102       r = INTERNAL_SYSCALL_CALL (fstatat64, fd, file, buf, flag);
103     #  else
104       /* 64-bit kABI outlier, e.g. sparc64.  */
105       struct kernel_stat64 kst64;
106       r = INTERNAL_SYSCALL_CALL (fstatat64, fd, file, &kst64, flag);
107       if (r == 0)
108         __cp_stat64_kstat64 (buf, &kst64);
109     #  endif
110     # endif
111     #else
112     # ifdef __NR_fstatat64
113       /* All kABIs with non-LFS support and with old 32-bit time_t support
114          e.g. arm, csky, i386, hppa, m68k, microblaze, nios2, sh, powerpc32,
115          and sparc32.  */
116       struct stat64 st64;
117       r = INTERNAL_SYSCALL_CALL (fstatat64, fd, file, &st64, flag);
118       if (r == 0)
119         {
120           /* Clear both pad and reserved fields.  */
121           memset (buf, 0, sizeof (*buf));
122
123           buf->st_dev = st64.st_dev,
124           buf->st_ino = st64.st_ino;
125           buf->st_mode = st64.st_mode;
126           buf->st_nlink = st64.st_nlink;
127           buf->st_uid = st64.st_uid;
128           buf->st_gid = st64.st_gid;
129           buf->st_rdev = st64.st_rdev;
130           buf->st_size = st64.st_size;
131           buf->st_blksize = st64.st_blksize;
132           buf->st_blocks  = st64.st_blocks;
133           buf->st_atim = valid_timespec_to_timespec64 (st64.st_atim);
134           buf->st_mtim = valid_timespec_to_timespec64 (st64.st_mtim);
135           buf->st_ctim = valid_timespec_to_timespec64 (st64.st_ctim);
136         }
137     # else
138       /* 64-bit kabi outlier, e.g. mips64 and mips64-n32.  */
139       struct kernel_stat kst;
140       r = INTERNAL_SYSCALL_CALL (newfstatat, fd, file, &kst, flag);
141       if (r == 0)
142         __cp_kstat_stat64_t64 (&kst, buf);
143     # endif
144     #endif
145
146       return r;
147     }

_IO_setb

设置_IO_buf_base 和_IO_buf_end

c 复制代码
327     void
328     _IO_setb (FILE *f, char *b, char *eb, int a)
329     {
330       if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
331         free (f->_IO_buf_base);
332       f->_IO_buf_base = b;
333       f->_IO_buf_end = eb;
334       if (a)
335         f->_flags &= ~_IO_USER_BUF;
336       else
337         f->_flags |= _IO_USER_BUF;
338     }
339     libc_hidden_def (_IO_setb)

__underflow

一般是在缓冲区都被用完了才会用__underflow

c 复制代码
267     int
268     __underflow (FILE *fp)
269     {
270       if (_IO_vtable_offset (fp) == 0 && _IO_fwide (fp, -1) != -1)
271         return EOF;
272
273       if (fp->_mode == 0)
274         _IO_fwide (fp, -1);
275       if (_IO_in_put_mode (fp))
276         if (_IO_switch_to_get_mode (fp) == EOF)
277           return EOF;
278       if (fp->_IO_read_ptr < fp->_IO_read_end)
279         return *(unsigned char *) fp->_IO_read_ptr;
280       if (_IO_in_backup (fp))
281         {
282           _IO_switch_to_main_get_area (fp);
283           if (fp->_IO_read_ptr < fp->_IO_read_end)
284             return *(unsigned char *) fp->_IO_read_ptr;
285         }
286       if (_IO_have_markers (fp))
287         {
288           if (save_for_backup (fp, fp->_IO_read_end))
289             return EOF;
290         }
291       else if (_IO_have_backup (fp))
292         _IO_free_backup_area (fp);
293       return _IO_UNDERFLOW (fp);
294     }
295     libc_hidden_def (__underflow)

然后调用_IO_new_file_underflow

_IO_new_file_underflow

c 复制代码
8
459     int
460     _IO_new_file_underflow (FILE *fp)
461     {
462       ssize_t count;
463
464       /* C99 requires EOF to be "sticky".  */
465       if (fp->_flags & _IO_EOF_SEEN)
466         return EOF;
467
468       if (fp->_flags & _IO_NO_READS)
469         {
470           fp->_flags |= _IO_ERR_SEEN;
471           __set_errno (EBADF);
472           return EOF;
473         }
474       if (fp->_IO_read_ptr < fp->_IO_read_end)
475         return *(unsigned char *) fp->_IO_read_ptr;
476
477       if (fp->_IO_buf_base == NULL)
478         {
479           /* Maybe we already have a push back pointer.  */
480           if (fp->_IO_save_base != NULL)
481             {
482               free (fp->_IO_save_base);
483               fp->_flags &= ~_IO_IN_BACKUP;
484             }
485           _IO_doallocbuf (fp);
486         }
487
488       /* FIXME This can/should be moved to genops ?? */
489       if (fp->_flags & (_IO_LINE_BUF|_IO_UNBUFFERED))
490         {
491           /* We used to flush all line-buffered stream.  This really isn't
492              required by any standard.  My recollection is that
493              traditional Unix systems did this for stdout.  stderr better
494              not be line buffered.  So we do just that here
495              explicitly.  --drepper */
496           _IO_acquire_lock (stdout);
497
498           if ((stdout->_flags & (_IO_LINKED | _IO_NO_WRITES | _IO_LINE_BUF))
499               == (_IO_LINKED | _IO_LINE_BUF))
500             _IO_OVERFLOW (stdout, EOF);
501
502           _IO_release_lock (stdout);
503         }
504
505       _IO_switch_to_get_mode (fp);
506
507       /* This is very tricky. We have to adjust those
508          pointers before we call _IO_SYSREAD () since
509          we may longjump () out while waiting for
510          input. Those pointers may be screwed up. H.J. */
511       fp->_IO_read_base = fp->_IO_read_ptr = fp->_IO_buf_base;
512       fp->_IO_read_end = fp->_IO_buf_base;
513       fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_write_end
514         = fp->_IO_buf_base;
515
516       count = _IO_SYSREAD (fp, fp->_IO_buf_base,
517                            fp->_IO_buf_end - fp->_IO_buf_base);
518       if (count <= 0)
519         {
520           if (count == 0)
521             fp->_flags |= _IO_EOF_SEEN;
522           else
523             fp->_flags |= _IO_ERR_SEEN, count = 0;
524       }
525       fp->_IO_read_end += count;
526       if (count == 0)
527         {
528           /* If a stream is read to EOF, the calling application may switch active
529              handles.  As a result, our offset cache would no longer be valid, so
530              unset it.  */
531           fp->_offset = _IO_pos_BAD;
532           return EOF;
533         }
534       if (fp->_offset != _IO_pos_BAD)
535         _IO_pos_adjust (fp->_offset, count);
536       return *(unsigned char *) fp->_IO_read_ptr;
537     }
538     libc_hidden_ver (_IO_new_file_underflow, _IO_file_underflow)

判断flag是否运行读,然后判断缓冲区区是否为空(_IO_buf__base),空就会调用_IO_doallocbuf ,然后最后会重置输入输出缓冲区为缓冲区开始地址,然后调用_IO_file_read从文件读数据到缓冲区上,然后在设置输入缓冲区的地址

_IO_file_read

c 复制代码
1128    ssize_t
1129    _IO_file_read (FILE *fp, void *buf, ssize_t size)
1130    {
1131      return (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0)
1132              ? __read_nocancel (fp->_fileno, buf, size)
1133              : __read (fp->_fileno, buf, size));
1134    }
1135    libc_hidden_def (_IO_file_read)
c 复制代码
   23 ssize_t
   24 __libc_read (int fd, void *buf, size_t nbytes)
   25 {
 ► 26   return SYSCALL_CANCEL (read, fd, buf, nbytes);
   27 }
   28 libc_hidden_def (__libc_read)

fwrite

_IO_fwrite

c 复制代码
29      size_t
30      _IO_fwrite (const void *buf, size_t size, size_t count, FILE *fp)
31      {
32        size_t request = size * count;
33        size_t written = 0;
34        CHECK_FILE (fp, 0);
35        if (request == 0)
36          return 0;
37        _IO_acquire_lock (fp);
38        if (_IO_vtable_offset (fp) != 0 || _IO_fwide (fp, -1) == -1)
39          written = _IO_sputn (fp, (const char *) buf, request);
40        _IO_release_lock (fp);
41        /* We have written all of the input in case the return value indicates
42           this or EOF is returned.  The latter is a special case where we
43           simply did not manage to flush the buffer.  But the data is in the
44           buffer and therefore written as far as fwrite is concerned.  */
45        if (written == request || written == EOF)
46          return count;
47        else
48          return written / size;
49      }
50      libc_hidden_def (_IO_fwrite)

_IO_sputn 会调用到_IO_new_file_xsputn函数

_IO_new_file_xsputn

c 复制代码
1195    size_t
1196    _IO_new_file_xsputn (FILE *f, const void *data, size_t n)
1197    {
1198      const char *s = (const char *) data;
1199      size_t to_do = n;
1200      int must_flush = 0;
1201      size_t count = 0;
1202
1203      if (n <= 0)
1204        return 0;
1205      /* This is an optimized implementation.
1206         If the amount to be written straddles a block boundary
1207         (or the filebuf is unbuffered), use sys_write directly. */
1208
1209      /* First figure out how much space is available in the buffer. */
1210      if ((f->_flags & _IO_LINE_BUF) && (f->_flags & _IO_CURRENTLY_PUTTING))
1211        {
1212          count = f->_IO_buf_end - f->_IO_write_ptr;
1213          if (count >= n)
1214            {
1215              const char *p;
1216              for (p = s + n; p > s; )
1217                {
1218                  if (*--p == '\n')
1219                    {
1220                      count = p - s + 1;
1221                      must_flush = 1;
1222                      break;
1223                    }
1224                }
1225            }
1226        }
1227      else if (f->_IO_write_end > f->_IO_write_ptr)
1228        count = f->_IO_write_end - f->_IO_write_ptr; /* Space available. */
1229
1230      /* Then fill the buffer. */
1231      if (count > 0)
1232        {
1233          if (count > to_do)
1234            count = to_do;
1235          f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
1236          s += count;
1237          to_do -= count;
1238        }
1239      if (to_do + must_flush > 0)
1240        {
1241          size_t block_size, do_write;
1242          /* Next flush the (full) buffer. */
1243          if (_IO_OVERFLOW (f, EOF) == EOF)
1244            /* If nothing else has to be written we must not signal the
1245               caller that everything has been written.  */
1246            return to_do == 0 ? EOF : n - to_do;
1247
1248          /* Try to maintain alignment: write a whole number of blocks.  */
1249          block_size = f->_IO_buf_end - f->_IO_buf_base;
1250          do_write = to_do - (block_size >= 128 ? to_do % block_size : 0);
1251
1252          if (do_write)
1253            {
pwndbg> 
1254              count = new_do_write (f, s, do_write);
1255              to_do -= count;
1256              if (count < do_write)
1257                return n - to_do;
1258            }
1259
1260          /* Now write out the remainder.  Normally, this will fit in the
1261             buffer, but it's somewhat messier for line-buffered files,
1262             so we let _IO_default_xsputn handle the general case. */
1263          if (to_do)
1264            to_do -= _IO_default_xsputn (f, s+do_write, to_do);
1265        }
1266      return n - to_do;
1267    }
1268    libc_hidden_ver (_IO_new_file_xsputn, _IO_file_xsputn)

首先判断行缓冲机制,然后没有就会判断输出缓冲区剩余长度,够的话会直接memcpy到缓冲区,为零或者不够输出都会调用_IO_OVERFLOW刷新缓冲区将缓冲区内容写到文件中去,然后判断是否是大块,是的话就直接调用new_do_write 直接将写入的内容不经过缓冲区写到文件里,然后剩余或者不是大块就通过_IO_default_xsputn 写入到缓冲区

_IO_new_file_overflow

c 复制代码
729     int
730     _IO_new_file_overflow (FILE *f, int ch)
731     {
732       if (f->_flags & _IO_NO_WRITES) /* SET ERROR */
733         {
734           f->_flags |= _IO_ERR_SEEN;
735           __set_errno (EBADF);
736           return EOF;
737         }
738       /* If currently reading or no buffer allocated. */
739       if ((f->_flags & _IO_CURRENTLY_PUTTING) == 0 || f->_IO_write_base == NULL)
740         {
741           /* Allocate a buffer if needed. */
742           if (f->_IO_write_base == NULL)
743             {
744               _IO_doallocbuf (f);
745               _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);
746             }
747           /* Otherwise must be currently reading.
748              If _IO_read_ptr (and hence also _IO_read_end) is at the buffer end,
749              logically slide the buffer forwards one block (by setting the
750              read pointers to all point at the beginning of the block).  This
751              makes room for subsequent output.
752              Otherwise, set the read pointers to _IO_read_end (leaving that
753              alone, so it can continue to correspond to the external position). */
754           if (__glibc_unlikely (_IO_in_backup (f)))
755             {
756               size_t nbackup = f->_IO_read_end - f->_IO_read_ptr;
757               _IO_free_backup_area (f);
758               f->_IO_read_base -= MIN (nbackup,
759                                        f->_IO_read_base - f->_IO_buf_base);
760               f->_IO_read_ptr = f->_IO_read_base;
761             }
762
763           if (f->_IO_read_ptr == f->_IO_buf_end)
764             f->_IO_read_end = f->_IO_read_ptr = f->_IO_buf_base;
765           f->_IO_write_ptr = f->_IO_read_ptr;
766           f->_IO_write_base = f->_IO_write_ptr;
767           f->_IO_write_end = f->_IO_buf_end;
768           f->_IO_read_base = f->_IO_read_ptr = f->_IO_read_end;
769
770           f->_flags |= _IO_CURRENTLY_PUTTING;
771           if (f->_mode <= 0 && f->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
772             f->_IO_write_end = f->_IO_write_ptr;
773         }
774       if (ch == EOF)
775         return _IO_do_write (f, f->_IO_write_base,
776                              f->_IO_write_ptr - f->_IO_write_base);
777       if (f->_IO_write_ptr == f->_IO_buf_end ) /* Buffer is really full */
778         if (_IO_do_flush (f) == EOF)
779           return EOF;
780       *f->_IO_write_ptr++ = ch;
781       if ((f->_flags & _IO_UNBUFFERED)
782           || ((f->_flags & _IO_LINE_BUF) && ch == '\n'))
783         if (_IO_do_write (f, f->_IO_write_base,
784                           f->_IO_write_ptr - f->_IO_write_base) == EOF)
785           return EOF;
786       return (unsigned char) ch;
787     }
788     libc_hidden_ver (_IO_new_file_overflow, _IO_file_overflow)

首先判断是否包含NO_Write,没有就判断_IO_write_base 是否为空,为空就会调用 _IO_doallocbuf (f); 745 _IO_setg (f, f->_IO_buf_base, f->_IO_buf_base, f->_IO_buf_base);_IO_doallocbuf 会申请分配缓冲区并将指针_IO_buf_base和_IO_buf_end赋值。然后调用_IO_setg ,最后调用_IO_do_write 将缓冲区内容写到文件中

c 复制代码
 // 这两个是宏, 就是设置 read 和 write 的三个指针都为 _IO_buf_base
      _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
      _IO_setp (fp, fp->_IO_buf_base, fp->_IO_buf_base);

_IO_do_write

c 复制代码
   421 int
   422 _IO_new_do_write (FILE *fp, const char *data, size_t to_do)
   423 {
   424   return (to_do == 0
 ► 425           || (size_t) new_do_write (fp, data, to_do) == to_do) ? 0 : EOF;
   426 }
   427 libc_hidden_ver (_IO_new_do_write, _IO_do_write)
   428 

new_do_write

c 复制代码
429     static size_t
430     new_do_write (FILE *fp, const char *data, size_t to_do)
431     {
432       size_t count;
433       if (fp->_flags & _IO_IS_APPENDING)
434         /* On a system without a proper O_APPEND implementation,
435            you would need to sys_seek(0, SEEK_END) here, but is
436            not needed nor desirable for Unix- or Posix-like systems.
437            Instead, just indicate that offset (before and after) is
438            unpredictable. */
439         fp->_offset = _IO_pos_BAD;
440       else if (fp->_IO_read_end != fp->_IO_write_base)
441         {
442           off64_t new_pos
443             = _IO_SYSSEEK (fp, fp->_IO_write_base - fp->_IO_read_end, 1);
444           if (new_pos == _IO_pos_BAD)
445             return 0;
446           fp->_offset = new_pos;
447         }
448       count = _IO_SYSWRITE (fp, data, to_do);
449       if (fp->_cur_column && count)
450         fp->_cur_column = _IO_adjust_column (fp->_cur_column - 1, data, count) + 1;
451       _IO_setg (fp, fp->_IO_buf_base, fp->_IO_buf_base, fp->_IO_buf_base);
452       fp->_IO_write_base = fp->_IO_write_ptr = fp->_IO_buf_base;
453       fp->_IO_write_end = (fp->_mode <= 0
454                            && (fp->_flags & (_IO_LINE_BUF | _IO_UNBUFFERED))
455                            ? fp->_IO_buf_base : fp->_IO_buf_end);
456       return count;
457     }

首先是否开启追加模式,没有开启就判断fp->_IO_read_end != fp->_IO_write_base然后看是否调用_IO_file_seek 去找到写入的位置,然后调用_IO_SYSWRITE 写入文件,最后刷新write缓冲区指针

_IO_file_seek

c 复制代码
1137    off64_t
1138    _IO_file_seek (FILE *fp, off64_t offset, int dir)
1139    {
1140      return __lseek64 (fp->_fileno, offset, dir);
1141    }
1142    libc_hidden_def (_IO_file_seek)

_IO_new_file_write

c 复制代码
1171    ssize_t
1172    _IO_new_file_write (FILE *f, const void *data, ssize_t n)
1173    {
1174      ssize_t to_do = n;
1175      while (to_do > 0)
1176        {
1177          ssize_t count = (__builtin_expect (f->_flags2
1178                                             & _IO_FLAGS2_NOTCANCEL, 0)
1179                               ? __write_nocancel (f->_fileno, data, to_do)
1180                               : __write (f->_fileno, data, to_do));
1181          if (count < 0)
1182            {
1183              f->_flags |= _IO_ERR_SEEN;
1184              break;
1185            }
1186          to_do -= count;
1187          data = (void *) ((char *) data + count);
1188        }
1189      n -= to_do;
1190      if (f->_offset >= 0)
1191        f->_offset += n;
1192      return n;
1193    }

_IO_do_flush

c 复制代码
#define _IO_do_flush(_f) \
  ((_f)->_mode <= 0                                                              \
   ? _IO_do_write(_f, (_f)->_IO_write_base,                                      \
                  (_f)->_IO_write_ptr-(_f)->_IO_write_base)                      \
   : _IO_wdo_write(_f, (_f)->_wide_data->_IO_write_base,                         \
                   ((_f)->_wide_data->_IO_write_ptr                              \
                    - (_f)->_wide_data->_IO_write_base)))

_IO_default_xsputn

c 复制代码
370     _IO_default_xsputn (FILE *f, const void *data, size_t n)
371     {
372       const char *s = (char *) data;
373       size_t more = n;
374       if (more <= 0)
375         return 0;
376       for (;;)
377         {
378           /* Space available. */
379           if (f->_IO_write_ptr < f->_IO_write_end)
380             {
381               size_t count = f->_IO_write_end - f->_IO_write_ptr;
382               if (count > more)
383                 count = more;
384               if (count > 20)
385                 {
386                   f->_IO_write_ptr = __mempcpy (f->_IO_write_ptr, s, count);
387                   s += count;
388                 }
389               else if (count)
390                 {
391                   char *p = f->_IO_write_ptr;
392                   ssize_t i;
393                   for (i = count; --i >= 0; )
394                     *p++ = *s++;
395                   f->_IO_write_ptr = p;
396                 }
397               more -= count;
398             }
399           if (more == 0 || _IO_OVERFLOW (f, (unsigned char) *s++) == EOF)
400             break;
401           more--;
402         }
403       return n - more;
404     }
405     libc_hidden_def (_IO_default_xsputn)

首先判断输出缓冲区剩余,如果超过20,就直接memcpy拷贝到输出缓冲区,否则是循环来拷贝,当缓冲区已经满了或者已经将数据全部写到缓冲区了,会检查是否还有数据需要写入(more非零)或调用_IO_OVERFLOW尝试刷新缓冲区并写入下一个字符。如果_IO_OVERFLOW返回EOF`(错误)或者数据全部写到缓冲区了,则中断循环。

flose

_IO_new_fclose

c 复制代码
32      int
33      _IO_new_fclose (FILE *fp)
34      {
35        int status;
36
37        CHECK_FILE(fp, EOF);
38
39      #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
40        /* We desperately try to help programs which are using streams in a
41           strange way and mix old and new functions.  Detect old streams
42           here.  */
43        if (_IO_vtable_offset (fp) != 0)
44          return _IO_old_fclose (fp);
45      #endif
46
47        /* First unlink the stream.  */
48        if (fp->_flags & _IO_IS_FILEBUF)
49          _IO_un_link ((struct _IO_FILE_plus *) fp);
50
51        _IO_acquire_lock (fp);
52        if (fp->_flags & _IO_IS_FILEBUF)
53          status = _IO_file_close_it (fp);
54        else
55          status = fp->_flags & _IO_ERR_SEEN ? -1 : 0;
56        _IO_release_lock (fp);
57        _IO_FINISH (fp);
58        if (fp->_mode > 0)
59          {
60            /* This stream has a wide orientation.  This means we have to free
61               the conversion functions.  */
62            struct _IO_codecvt *cc = fp->_codecvt;
63
64            __libc_lock_lock (__gconv_lock);
65            __gconv_release_step (cc->__cd_in.step);
66            __gconv_release_step (cc->__cd_out.step);
67            __libc_lock_unlock (__gconv_lock);
68          }
69        else
70          {
71            if (_IO_have_backup (fp))
72              _IO_free_backup_area (fp);
73          }
74        _IO_deallocate_file (fp);
75        return status;
76      }
77
78      versioned_symbol (libc, _IO_new_fclose, _IO_fclose, GLIBC_2_1);
79      strong_alias (_IO_new_fclose, __new_fclose)
80      versioned_symbol (libc, __new_fclose, fclose, GLIBC_2_1);

然后执行_IO_un_link

从链表上摘除

c 复制代码
0
51      void
52      _IO_un_link (struct _IO_FILE_plus *fp)
53      {
54        if (fp->file._flags & _IO_LINKED)
55          {
56            FILE **f;
57      #ifdef _IO_MTSAFE_IO
58            _IO_cleanup_region_start_noarg (flush_cleanup);
59            _IO_lock_lock (list_all_lock);
60            run_fp = (FILE *) fp;
61            _IO_flockfile ((FILE *) fp);
62      #endif
63            if (_IO_list_all == NULL)
64              ;
65            else if (fp == _IO_list_all)
66              _IO_list_all = (struct _IO_FILE_plus *) _IO_list_all->file._chain;
67            else
68              for (f = &_IO_list_all->file._chain; *f; f = &(*f)->_chain)
69                if (*f == (FILE *) fp)
70                  {
71                    *f = fp->file._chain;
72                    break;
73                  }
74            fp->file._flags &= ~_IO_LINKED;
75      #ifdef _IO_MTSAFE_IO
76            _IO_funlockfile ((FILE *) fp);
77            run_fp = NULL;
78            _IO_lock_unlock (list_all_lock);
79            _IO_cleanup_region_end (0);
80      #endif
81          }
82      }
83      libc_hidden_def (_IO_un_link)

_IO_new_file_close_it

c 复制代码
  int
127     _IO_new_file_close_it (FILE *fp)
128     {
129       int write_status;
130       if (!_IO_file_is_open (fp))
131         return EOF;
132
133       if ((fp->_flags & _IO_NO_WRITES) == 0
134           && (fp->_flags & _IO_CURRENTLY_PUTTING) != 0)
135         write_status = _IO_do_flush (fp);
136       else
137         write_status = 0;
138
139       _IO_unsave_markers (fp);
140
141       int close_status = ((fp->_flags2 & _IO_FLAGS2_NOCLOSE) == 0
142                           ? _IO_SYSCLOSE (fp) : 0);
143
144       /* Free buffer. */
145       if (fp->_mode > 0)
146         {
147           if (_IO_have_wbackup (fp))
148             _IO_free_wbackup_area (fp);
149           _IO_wsetb (fp, NULL, NULL, 0);
150           _IO_wsetg (fp, NULL, NULL, NULL);
151           _IO_wsetp (fp, NULL, NULL);
152         }
153       _IO_setb (fp, NULL, NULL, 0);
154       _IO_setg (fp, NULL, NULL, NULL);
155       _IO_setp (fp, NULL, NULL);
156
157       _IO_un_link ((struct _IO_FILE_plus *) fp);
158       fp->_flags = _IO_MAGIC|CLOSED_FILEBUF_FLAGS;
159       fp->_fileno = -1;
160       fp->_offset = _IO_pos_BAD;
161
162       return close_status ? close_status : write_status;
163     }
164     libc_hidden_ver (_IO_new_file_close_it, _IO_file_close_it)

检查文件是否打开,然后如果支持写入就将缓冲区的内容写入文件(_IO_do_flush ),然后执行_IO_SYSCLOSE 即_IO_file_close ,最后将fie结构的一些指针设置为null,然后再_IO_un_link 一次

_IO_file_close

c 复制代码
   1163 _IO_file_close (FILE *fp)
   1164 {
   1165   /* Cancelling close should be avoided if possible since it leaves an
   1166      unrecoverable state behind.  */
   1167   return __close_nocancel (fp->_fileno);
 ► 1168 }
   1169 libc_hidden_def (_IO_file_close)
c 复制代码
   23 int
   24 __close_nocancel (int fd)
   25 {
 ► 26   return INLINE_SYSCALL_CALL (close, fd);
   27 }
   28 libc_hidden_def (__close_nocancel)

然后执行_IO_FINISH

_IO_new_file_finish

c 复制代码
 void
167     _IO_new_file_finish (FILE *fp, int dummy)
168     {
169       if (_IO_file_is_open (fp))
170         {
171           _IO_do_flush (fp);
172           if (!(fp->_flags & _IO_DELETE_DONT_CLOSE))
173             _IO_SYSCLOSE (fp);
174         }
175       _IO_default_finish (fp, 0);
176     }
177     libc_hidden_ver (_IO_new_file_finish, _IO_file_finish)

由于上面已经关闭了,一般会直接执行_IO_default_finish

_IO_default_finish

c 复制代码
598
599     void
600     _IO_default_finish (FILE *fp, int dummy)
601     {
602       struct _IO_marker *mark;
603       if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
604         {
605           free (fp->_IO_buf_base);
606           fp->_IO_buf_base = fp->_IO_buf_end = NULL;
607         }
608
609       for (mark = fp->_markers; mark != NULL; mark = mark->_next)
610         mark->_sbuf = NULL;
611
612       if (fp->_IO_save_base)
613         {
614           free (fp->_IO_save_base);
615           fp->_IO_save_base = NULL;
616         }
617
618       _IO_un_link ((struct _IO_FILE_plus *) fp);
619
620     #ifdef _IO_MTSAFE_IO
621       if (fp->_lock != NULL)
622         _IO_lock_fini (*fp->_lock);
623     #endif
624     }
625     libc_hidden_def (_IO_default_finish)

释放结束各种资源

_IO_deallocate_file

然后会执行

c 复制代码
if (fp->_mode > 0)
59          {
60            /* This stream has a wide orientation.  This means we have to free
61               the conversion functions.  */
62            struct _IO_codecvt *cc = fp->_codecvt;
63
64            __libc_lock_lock (__gconv_lock);
65            __gconv_release_step (cc->__cd_in.step);
66            __gconv_release_step (cc->__cd_out.step);
67            __libc_lock_unlock (__gconv_lock);
68          }
69        else
70          {
71            if (_IO_have_backup (fp))
72              _IO_free_backup_area (fp);
73          }
74        _IO_deallocate_file (fp);
  • 检查文件流模式:

    • if (fp->_mode > 0) 检查文件流是否以宽字符模式打开(例如,涉及多字节编码如UTF-16或UTF-32)。fp->_mode大于0表明流具有宽字符定向。
  • 宽字符编码资源释放:

    • 如果流是宽字符模式,执行如下操作:
      • 获取编码转换器结构体指针:struct _IO_codecvt *cc = fp->_codecvt;
      • 加锁以确保线程安全:__libc_lock_lock(__gconv_lock);
      • 释放输入和输出转换步骤(可能是字符编码转换的内部状态):__gconv_release_step(cc->__cd_in.step)__gconv_release_step(cc->__cd_out.step)
      • 解锁:__libc_lock_unlock(__gconv_lock);
  • 备份区域处理:

    • 否则(即文件流不是宽字符模式),则检查是否存在备份区域:
      • if (_IO_have_backup(fp)) 确认文件流是否有备份区域,备份区域通常用于实现诸如撤销写入等功能。
      • 如果存在,则释放备份区域:_IO_free_backup_area(fp);
  • 文件流资源释放:

    • 不论哪种情况,最终都会执行:
      • _IO_deallocate_file(fp); 释放整个文件流结构体及其关联的所有资源。
c 复制代码
static inline void
_IO_deallocate_file (FILE *fp)
{
  /* The current stream variables.  */
  if (fp == (FILE *) &_IO_2_1_stdin_ || fp == (FILE *) &_IO_2_1_stdout_
      || fp == (FILE *) &_IO_2_1_stderr_)
    return;
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
  if (_IO_legacy_file (fp))
    return;
#endif
  free (fp);
}

检查传入的fp是否是指向标准输入stdin、标准输出stdout或标准错误stderr的文件流。不是就会free掉FILE结构体

相关推荐
橘子真甜~22 天前
Linux操作系统3-文件与IO操作1(从C语言IO操作到系统调用)
linux·运维·服务器·c语言·io·文件操作·文件fd
charlie1145141912 个月前
嵌入式Linux入门具备:C语言基础与基本驱动学习(2):Linux GIibc IO基础
c语言·学习·c·io·嵌入式软件
我要学编程(ಥ_ಥ)2 个月前
初始JavaEE篇 —— 文件操作与IO
java·开发语言·java-ee·io·文件操作
Mr.W.T2 个月前
NIO 核心知识总结
io·nio
奔跑的废柴2 个月前
【黑马Redis原理篇】Redis网络模型
网络·redis·io
一丝晨光3 个月前
标准输入输出
java·c++·python·c#·go·c·io
闲人编程3 个月前
Python实现Socket.IO的完整指南
开发语言·python·网络编程·io·socket·异步
闲人编程3 个月前
Python实现 Socket.IO 的在线游戏场景
开发语言·python·游戏·网络编程·io·socket·异步
枫叶丹43 个月前
【在Linux世界中追寻伟大的One Piece】五种IO模型和阻塞IO
java·运维·开发语言·网络·jvm·io
promise5244 个月前
Linux性能监控神器:深入top命令详解与磁盘IO分析技巧
linux·运维·服务器·后端·性能优化·bash·io