IO-源码阅读 glibc 2.35

文章目录

  • 参考
  • 缓存机制
  • IO_FILE_PLUS
  • fopen
    • fopen_internal
    • _IO_no_init
      • _IO_old_init
    • _IO_new_file_init_internal
      • _IO_link_in
    • _IO_new_file_fopen
      • _IO_file_open
  • fread
    • _IO_fread
    • _IO_sgetn
    • _IO_doallocbuf
      • _IO_file_doallocate
      • _IO_file_stat
      • _IO_setb
    • __underflow
      • _IO_new_file_underflow
      • _IO_file_read
  • fwrite
    • _IO_fwrite
    • _IO_new_file_xsputn
      • _IO_new_file_overflow
      • _IO_do_write
      • new_do_write
      • _IO_file_seek
      • _IO_new_file_write
      • _IO_do_flush
    • _IO_default_xsputn
  • flose
    • _IO_new_fclose
    • _IO_un_link
    • _IO_new_file_close_it
      • _IO_file_close
    • _IO_new_file_finish
      • _IO_default_finish
      • _IO_deallocate_file

参考

https://wiki.wgpsec.org/knowledge/ctf/iofile.html
https://blog.wingszeng.top/pwn-glibc-file-struct-and-related-functions/#%E8%AF%BB%E5%8F%96%E7%BC%93%E5%86%B2%E5%8C%BA

缓存机制

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

IO_FILE_PLUS

fopen

fopen就是IO_new_fopen,首先会进入fopen_internal

fopen_internal

在这里插入图片描述

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;
#endifstruct _IO_wide_data wd;} *new_f = (struct locked_FILE *) malloc (sizeof (struct locked_FILE));if (new_f == NULL)return NULL;
#ifdef _IO_MTSAFE_IOnew_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

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

在这里插入图片描述

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

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     }

_IO_link_in

      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

 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

    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 函数


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

   407 size_t408 _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 函数

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

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

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

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

      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

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

 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

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

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

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

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)
   23 ssize_t24 __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

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

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

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 将缓冲区内容写到文件中

 // 这两个是宏, 就是设置 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

   421 int422 _IO_new_do_write (FILE *fp, const char *data, size_t to_do)423 {424   return (to_do == 0425           || (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


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

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

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

#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

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

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

_IO_un_link

从链表上摘除

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

  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

   1163 _IO_file_close (FILE *fp)1164 {1165   /* Cancelling close should be avoided if possible since it leaves an1166      unrecoverable state behind.  */1167   return __close_nocancel (fp->_fileno);1168 }1169 libc_hidden_def (_IO_file_close)
   23 int24 __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

 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

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

然后会执行

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); 释放整个文件流结构体及其关联的所有资源。
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;
#endiffree (fp);
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/25153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Cloud Networking] Layer 2

文章目录 1. 什么是Mac Address?2. 如何查找MAC地址&#xff1f;3. 二层数据交换4. [Layer 2 Protocol](https://blog.csdn.net/settingsun1225/article/details/139552315) 1. 什么是Mac Address? MAC 地址是计算机的唯一48位硬件编码&#xff0c;嵌入到网卡中。 MAC地址也…

英特尔:AI落地,未来已来

引言 随着AI技术的发展和大模型的普及&#xff0c;人工智能正在逐渐渗透到我们的日常生活中。2023年5月底&#xff0c;我参加了台北的英特尔技术展&#xff0c;深入了解了英特尔在AI个人电脑领域的最新进展。本文将详细介绍英特尔的新一代移动处理器Lunar Lake&#xff0c;以及…

LabVIEW 与组态软件在自动化系统中的应用比较与选择

LabVIEW 确实在非标单机设备、测试和测量系统中有着广泛的应用&#xff0c;特别是在科研、教育、实验室和小型自动化设备中表现突出。然而&#xff0c;LabVIEW 也具备一定的扩展能力&#xff0c;可以用于更复杂和大型的自动化系统。以下是对 LabVIEW 与组态软件在不同应用场景中…

【C++】——Stack与Queue(含优先队列(详细解读)

前言 之前数据结构中是栈和队列&#xff0c;我们分别用的顺序表和链表去实现的&#xff0c;但是对于这里的栈和队列来说&#xff0c;他们是一种容器&#xff0c;更准确来说是一种容器适配器 ✨什么是容器适配器&#xff1f; 从他们的模板参数可以看出&#xff0c;第二个参数模…

Kafka 架构

1 整体架构 1.1 Zookeeper Zookeeper 是一个分布式协调服务&#xff0c;用于管理 Kafka 的元数据。它负责维护 Kafka 集群的配置信息、Broker 列表和分区的 Leader 信息。 Zookeeper 确保了 Kafka 集群的高可用性和可靠性。 但 Zookeeper 已经成为 Kafka 性能瓶颈&#xff0c;…

SmartDraw Suite Edition 画图软件画表格内存示意图的使用方法

总述&#xff1a;遇到不会画的&#xff0c;比如如何画一条虚线&#xff0c;先将 虚线 翻译成英文&#xff0c;然后在 help 中查询。 新建的时候选择如下&#xff1a; 一、选择 Forms->Blank Form 二、画表格&#xff1a; 三、画箭头&#xff1a;先选择1在选择2 四、编辑文…

ASUS华硕ROG幻14Air笔记本GA403UI(UI UV UU UJ)工厂模式原厂Windows11系统安装包,带MyASUS in WinRE重置还原

适用型号&#xff1a;GA403UI、GA403UV、GA403UU、GA403UJ 链接&#xff1a;https://pan.baidu.com/s/1tz8PZbYKakfvUoXafQPLIg?pwd1mtc 提取码&#xff1a;1mtc 华硕原装WIN11系统工厂包带有ASUS RECOVERY恢复功能、自带面部识别,声卡,显卡,网卡,蓝牙等所有驱动、出厂主题…

今日早报 每日精选15条新闻简报 每天一分钟 知晓天下事 6月9日,星期日

每天一分钟&#xff0c;知晓天下事&#xff01; 2024年6月9日 星期日 农历五月初四 1、 人社部&#xff1a;个人养老金开户人数已超6000万&#xff0c;其中31岁至40岁的中高收入人群是开户、缴费和购买产品的主力军。 2、 医保局刊文&#xff1a;研究显示集采仿制药替代原研药…

VSC++: 民意调查比例法

void 民意调查比例法() {//缘由https://bbs.csdn.net/topics/396521294?page1#post-411408461从题目描述看&#xff1a;902/3~300.7&#xff0c;1498/5~299.6也就是大约求2个数的公约数&#xff0c;并使得这个公约数尽量求出最小误差&#xff1f;且商小于某值。int a 0, aa …

物理安全防护如何创新强化信息安全体系?

物理安全防护是信息安全体系的重要组成部分&#xff0c;它通过保护实体设施、设备和介质等&#xff0c;防止未授权访问、破坏、盗窃等行为&#xff0c;从而为信息系统提供基础的安全保障。要创新强化信息安全体系中的物理安全防护&#xff0c;可以从以下几个方面着手&#xff1…

VBA高级应用30例应用2实现在列表框内及列表框间实现数据拖动

《VBA高级应用30例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…

Facebook:社交世界的引领者

导语 在当今数字化时代&#xff0c;Facebook已经成为了人们社交生活的重要一环。然而&#xff0c;除了成为社交媒体的象征外&#xff0c;它还在不断探索并领导着社交世界的新方向。 1. 社交平台的发展者 Facebook不仅仅是一个社交平台&#xff0c;更是社交方式的引领者。从其…

MathType7.8永久破解版下载 让数学学习变得简单有趣!

大家好&#xff0c;我是科技评论家。今天给大家推荐一款非常实用的数学公式编辑器——MathType 7.8&#xff01;&#x1f4f1;&#x1f4b0; 在数字化时代&#xff0c;学术研究、教学和科研领域中的数学公式编辑需求越来越高。而MathType 7.8作为一个广受欢迎的数学公式编辑器&…

swaks一键启动邮箱信息测试(KALI工具系列十九)

目录 1、KALI LINUX 简介 2、swak工具简介 3、临时邮箱 4、操作实例 4.1 测试邮箱连通性 4.2 假冒发送方 4.3 发送文件 5、总结 1、KALI LINUX 简介 Kali Linux 是一个功能强大、多才多艺的 Linux 发行版&#xff0c;广泛用于网络安全社区。它具有全面的预安装工具和功…

MSP432E401Y Launchpad硬件电路

MSP432E401Y是一款32位Arm Cortex-M4F内核的MCU&#xff0c;主频120MHz、256KB SRAM、1MB Flash、6KB EEPROM&#xff0c;具有丰富的通信外设&#xff0c;例如支持以太网、2个CAN、8个UART、4个QSSI(SPI)、10 个I2C; 同时还有2个12 位SAR的ADC模块&#xff0c;每个模块支持高…

探索智慧景区的总体架构与应用

背景&#xff1a; 在旅游业快速发展的今天&#xff0c;智慧景区已成为提升景区管理水平、提高游客体验的重要手段之一。智慧景区系统的总体架构设计与应用&#xff0c;将现代信息技术与景区管理相结合&#xff0c;为景区的运营管理和游客服务提供了新的思路和解决方案。本文将…

【诈骗离你我很近】中国同胞进来看看国外诈骗新套路。

前几天一个老外经常在CSDN给我发消息&#xff0c;我最开始很警惕&#xff0c;不过聊了大概半个月&#xff0c;我就没怎么怀疑他了&#xff0c;而且还很高兴认识了一个外国朋友。这半个月聊天内容很正常&#xff0c;就聊些中国的小习惯&#xff0c;让我教他用筷子。还问我有哪些…

【BUG】已解决: No module named ‘torch._six

已解决&#xff1a;No module named ‘torch._six 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身&#xff0c;就职于医疗科技公司&#xff0c;热衷分享知识&#xff0c;目前是武汉城市开发者社区主…

GPT-4欺骗人类的惊人成功率达99.16%!

PNAS重磅研究揭示&#xff0c;LLM推理能力越强欺骗率越高&#xff01;&#xff01; 此前&#xff0c;MIT的研究发现&#xff0c;AI在各类游戏中为了达到目的&#xff0c;不择手段&#xff0c;学会用佯装和歪曲偏好等方式欺骗人类。 GPT-4o深夜发布&#xff01;Plus免费可用&…

数据加密验签机的工作原理

数据加密验签机&#xff0c;作为网络安全领域的关键设备&#xff0c;其重要性不言而喻。以下是对数据加密验签机的详细介绍&#xff1a; 一、引言 在数字化时代&#xff0c;数据的机密性、完整性和真实性是企业和个人都极为关注的问题。数据加密验签机&#xff0c;正是为了解决…