IO-源码阅读 glibc 2.35

news2024/11/25 15:56:55

文章目录

  • 参考
  • 缓存机制
  • 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;
#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

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

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_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

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 int
   422 _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 an
   1166      unrecoverable state behind.  */
   1167   return __close_nocancel (fp->_fileno);1168 }
   1169 libc_hidden_def (_IO_file_close)

   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

 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;
#endif
  free (fp);
}

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

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

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

相关文章

windows软件手动设置开机自启

博主需求 由于很多线上课程使用outlook进行教学&#xff0c;课程链接都关联到outlook日历中了&#xff0c;只要保持outlook是打开的状态就能收到上课提醒&#xff0c;非常方便。 但是有时候会忘记打开outlook查看&#xff0c;我偶尔会错过一些提醒QAQ。 所以如何让outlook常…

Qwen2大模型微调入门实战(完整代码)

Qwen2是通义千问团队的开源大语言模型&#xff0c;由阿里云通义实验室研发。以Qwen2作为基座大模型&#xff0c;通过指令微调的方式实现高准确率的文本分类&#xff0c;是学习大语言模型微调的入门任务。 指令微调是一种通过在由&#xff08;指令&#xff0c;输出&#xff09;对…

解读下/etc/network/interfaces配置文件

/etc/network/interfaces 是一个常见的网络配置文件&#xff0c;通常在 Debian 及其衍生版本的 Linux 发行版中使用。该文件用于配置网络接口和网络连接参数&#xff0c;允许用户手动设置网络连接的属性&#xff0c;包括 IP 地址、子网掩码、网关、DNS 服务器等。 以下是一个可…

LeetCode热题100—链表(二)

19.删除链表的倒数第N个节点 题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 …

人工智能程序员应该有什么职业素养?

人工智能程序员应该有什么职业素养&#xff1f; 面向企业需求去学习AI必备技能实战能力实战能力提升策略 面向企业需求去学习 如果想要应聘AI相关的岗位&#xff0c;就需要知道HR和管理层在招聘时需要考察些什么&#xff0c;面向招聘的需求去学习就能具备AI程序员该有的职业素…

Golang发送邮件如何验证身份?有哪些限制?

Golang发送邮件需要哪些库&#xff1f;怎么设置邮件发送的参数&#xff1f; 对于开发者而言&#xff0c;使用Golang发送邮件是一种常见需求。然而&#xff0c;在发送邮件的过程中&#xff0c;验证身份是一个至关重要的环节&#xff0c;它确保了邮件的可靠性和安全性。A将探讨G…

linux业务代码性能优化点

planning优化的一些改动----------> 减少值传递&#xff0c;多用引用来传递 <---------- // ----------> 减少值传递&#xff0c;多用引用来传递 <---------- // 例1&#xff1a; class A{}; std::vector<A> v; // for(auto elem : v) {} // 不建议&#xff…

FreeRTOS实时系统 在任务中增加数组等相关操作 导致单片机起不来或者挂掉

在调试串口任务中增加如下代码&#xff0c;发现可以用keil进行仿真&#xff0c;但是烧录程序后&#xff0c;调试串口没有打印&#xff0c;状态灯也不闪烁&#xff0c;单片机完全起不来 博主就纳了闷了&#xff0c;究竟是什么原因&#xff0c;这段代码可是公司永流传的老代码了&…

【小白专用24.6.8】c#异步方法 async task调用及 await运行机制

await是C#中用于等待异步操作完成的关键字。它通常用于异步方法内部&#xff0c;使得在等待异步操作期间&#xff0c;线程可以继续执行其他操作&#xff0c;从而保持程序的响应性。 在使用await时&#xff0c;需要注意以下几点&#xff1a; 1. async修饰符&#xff1a; 使用…

Mac环境下,简单反编译APK

一、下载jadx包 https://github.com/skylot/jadx/releases/tag/v1.4.7 下载里面的这个&#xff1a;下载后&#xff0c;找个干净的目录解压&#xff0c;我是放在Downloads下面 二、安装及启动 下载和解压 jadx&#xff1a; 下载 jadx-1.4.7.zip 压缩包。将其解压到你希望的目…

C++ 史上首次超越 C,跃至榜二

TIOBE 公布了 2024 年 6 月的编程语言排行榜。 C在本月的TIOBE指数中成功超越了C&#xff0c;成为新的第二名。它是一种被广泛应用于嵌入式系统、游戏开发和金融交易软件等领域的编程语言。这次的排名是C在TIOBE指数中的历史最高位&#xff0c;同时也是C语言的历史最低位。 T…

排序-读取数据流并实时返回中位数

目录 一、问题描述 二、解题思路 1.顺序表排序法 2.使用大根堆、小根堆 三、代码实现 1.顺序表排序法实现 2.大根堆、小根堆法实现 四、刷题链接 一、问题描述 二、解题思路 1.顺序表排序法 &#xff08;1&#xff09;每次读取一个数就对列表排一次序&#xff0c;对排…

使用Python批量处理Excel的内容

正文共&#xff1a;1500 字 10 图&#xff0c;预估阅读时间&#xff1a;1 分钟 在前面的文章中&#xff08;如何使用Python提取Excel中固定单元格的内容&#xff09;&#xff0c;我们介绍了如何安装Python环境和PyCharm工具&#xff0c;还利用搭好的环境简单测试了一下ChatGPT提…

CPP入门:CPP的内存管理模式

一.new和delete操作自定义类型 1.1C语言的内存管理 在传统的C语言中&#xff0c;malloc和free是无法调用类的构造和析构函数的 #include <iostream> using namespace std; class kuzi { public:kuzi(int a, int b):_a(a), _b(b){cout << "我构造啦" &…

卷积的计算过程

卷积的计算过程 flyfish 包括手动计算&#xff0c;可视化使用torch.nn.Conv2d实现 示例 import torch import torch.nn as nn# 定义输入图像 input_image torch.tensor([[1, 2, 3, 0, 1],[0, 1, 2, 3, 4],[2, 3, 0, 1, 2],[1, 2, 3, 4, 0],[0, 1, 2, 3, 4] ], dtypetorch.f…

20240609如何查询淘宝的历史价格

20240609如何查询淘宝的历史价格 2024/6/9 18:39 百度&#xff1a;淘宝历史价格 淘宝历史价格查询网站 https://zhuanlan.zhihu.com/p/670972171 30秒学会淘宝商品历史价格查询&#xff01; https://item.taobao.com/item.htm?id693104421622&pidmm_29415502_2422500430_1…

AI菜鸟向前飞 — LangChain系列之十七 - 剖析AgentExecutor

AgentExecutor 顾名思义&#xff0c;Agent执行器&#xff0c;本篇先简单看看LangChain是如何实现的。 先回顾 AI菜鸟向前飞 — LangChain系列之十四 - Agent系列&#xff1a;从现象看机制&#xff08;上篇&#xff09; AI菜鸟向前飞 — LangChain系列之十五 - Agent系列&#…

sqlilabs靶场安装

05-sqllabs靶场安装 1 安装 1 把靶场sqli-labs-master.zip上传到 /opt/lampp/htdocs 目录下 2 解压缩 unzip sqli-labs-master.zip3 数据库配置 找到配置文件,修改数据库配置信息 用户名密码&#xff0c;修改为你lampp下mysql的用户名密码&#xff0c;root/123456host:la…

GraphQL(6):认证与中间件

下面用简单来讲述GraphQL的认证示例 1 实现代码 在代码中添加过滤器&#xff1a; 完整代码如下&#xff1a; const express require(express); const {buildSchema} require(graphql); const grapqlHTTP require(express-graphql).graphqlHTTP; // 定义schema&#xff0c;…

计算机网络:数据链路层 - 扩展的以太网

计算机网络&#xff1a;数据链路层 - 扩展的以太网 集线器交换机自学习算法单点故障 集线器 这是以前常见的总线型以太网&#xff0c;他最初使用粗铜轴电缆作为传输媒体&#xff0c;后来演进到使用价格相对便宜的细铜轴电缆。 后来&#xff0c;以太网发展出来了一种使用大规模…