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;
#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.mfbz.cn/a/693914.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入Llama2:掌握未来语言模型的秘密

Llama2是一个基于Transformer架构的大型语言模型&#xff0c;它旨在处理和理解大规模的文本数据。作为技术人员&#xff0c;了解Llama2的工作原理、模型结构和训练方法对于有效利用该模型至关重要。本文将详细介绍Llama2的基本概念、主要作用、使用方法及注意事项。 一、简介 …

Linux---Linux编译器-gcc与g++的使用

GCC是以GPL许可证所发行的自由软件&#xff0c;也是GNU计划的关键部分。GCC的初衷是为GNU操作系统专门编写一款编译器&#xff0c;现已被大多数类Unix操作系统&#xff08;如Linux、BSD、MacOS X等&#xff09;采纳为标准的编译器。 gcc是专门用来编译C语言的&#xff0c;而g是…

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 …

Django Forbidden (CSRF cookie not set.)解决办法

解决办法就是在setting.py文件中注释&#xff1a; django.middleware.csrf.CsrfViewMiddleware, 这个中间件是为了防止跨站请求伪造的&#xff0c;平时用网页表单请求时&#xff0c;post提交是没有问题的&#xff0c;但是用api调用时就会被禁止&#xff0c;为了能使用接口调用…

【Java面试】十七、并发篇(上)

文章目录 1、synchronized关键字的底层原理&#xff1a;Monitor2、synchronized相关2.1 为什么说synchronized是重量级锁2.2 synchronized锁升级之偏向锁2.3 synchronized锁升级之轻量级锁 3、Java内存模型JMM4、CAS4.1 CAS流程4.2 CAS底层实现 5、volatile关键字的理解5.1 可见…

使用python绘制季节图

使用python绘制季节图 季节图效果代码 季节图 季节图&#xff08;Seasonal Plot&#xff09;是一种数据可视化图表&#xff0c;用于展示时间序列数据的季节性变化。它通过将每个时间段&#xff08;如每个月、每个季度&#xff09;的数据绘制在同一张图表上&#xff0c;使得不同…

文件怎么去重?5个技巧,教你删除重复文件!

一般来说&#xff0c;在处理大量文件时&#xff0c;你可能会遇到重复的类似文件。这些文件占据了电脑上不必要的磁盘空间&#xff0c;导致系统性能下降。而这些文件可以是不同类型的&#xff0c;如照片、视频、音频、存档、文档等。正因如此&#xff0c;您需要通过文件去重来删…

SpringBoot+Vue学科竞赛系统(前后端分离)

技术栈 JavaSpringBootMavenMySQLMyBatisVueShiroElement-UI 角色对应功能 学生教师管理员 功能截图

SQL Developer迁移第三方数据库单表到Oracle

在SQL Developer中&#xff0c;除可用Migration Wizard迁移第三方数据库到Oracle外&#xff0c;单表的迁移可以用Copy To Oracle ...菜单。右键单击源表即可。 本例的源表为MySQL数据库employees中的表&#xff1a;departments。 Options页面&#xff1a;指定目标库&#xff…

【零基础一看就会】Python爬虫从入门到应用(下)

目录 一、urllib的学习 1.1 urllib介绍 1.2 urllib的基本方法介绍 urllib.Request &#xff08;1&#xff09;构造简单请求 &#xff08;2&#xff09;传入headers参数 &#xff08;3&#xff09;传入data参数 实现发送post请求&#xff08;示例&#xff09; response.…

RDK X3(aarch64) 测试手柄

0. 环境 - 亚博智能的ROSMASTER-X3 标准版 - XDK X3 1.0 - 冰原狼等win10免驱的手柄 1. RDK X3 1.0 串口通信 波特率 921600 root/root mobaterm -> Session -> VNC -> 192.168.8.108:5900 -> runrise 2. 测试 ROSMASTER-X3 标准版 配套的手柄 安装 …

umap降维,c++用法纪实

全是血泪&#xff0c;可惜对于大量数据&#xff0c;速度还是太慢。 一、代码 // ConsoleApplication2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream>#include "knncolle/knncolle.hpp" #include "Umap.…

登Cell Press子刊,武汉理工大学团队基于集成学习提出简化电化学模型,0.17s完成3500s的1C恒流放电

2022 年 7 月&#xff0c;不老男神林志颖突发车祸&#xff0c;作为专业赛车手的他驾驶的特斯拉 Model X 在行驶过程中忽然偏离既定轨迹&#xff0c;一头撞向路边的隔离带&#xff0c;随后车辆起火&#xff0c;并在救援车拖吊过程中二次起火&#xff0c;最终整辆车被烧到只剩下了…

解决Win10系统ping不通、无法远程的问题

1、概述 某天要使用微软的远程桌面程序mstsc.exe远程到旁边的一台测试电脑上,结果远程不了,ping都ping不通,于是详细研究了这个问题。在此大概地记录一下该问题排查的过程,以供参考。 2、ping不通 使用mstsc.exe远程到测试电脑,远程不了,没有反应。于是手动ping一…

股票数据集2-纳斯达克NASDAQ 100 分析

1. 数据清洗 用邻近均值的方法&#xff0c;去掉Non_Padding中的NaN数据 这里没用df.fillna(), 因为其只有前向(ffill )和 后向 (bfill) 插值&#xff0c;不适合大量连续的NaN pd转换为np&#xff0c;写一个函数, 返回np数组的空值&#xff0c;lambda的匿名函数返回y轴空值的索…

TinyVision V851s 使用 OpenCV + NPU 实现 Mobilenet v2 目标分类识别

用39块钱的V851se视觉开发板做了个小相机。 可以进行物品识别、自动追焦&#xff01; 这个超低成本的小相机是在V851se上移植使用全志在线开源版本的Tina Linux与OpenCV框架开启摄像头拍照捕获视频&#xff0c;并结合NPU实现Mobilenet v2目标分类识别以及运动追踪等功能......并…

Web学习_sqli-labs_1~10关

less1-GET-Error based - Single quotes - String &#xff08;基于错误的GET单引号字符型注入&#xff09; 我每次操作都会在Hackbar中&#xff0c;代码都在Hackbar框中&#xff0c;可放大看 有题目知道了是字符型注入&#xff0c;我们先判断表格有几列&#xff0c;可以发现…

层次聚类分析星

clc,clear a [73,40,7;60,15,5;61,19,2;34,18,6;67,126,10;91,40,4;101,40,13;81,40,6;88,40,8;122,40,17;102,50,17;87,50,12;110,50,14;164,50,17;40,30,1;76,40,17;118,50,9;160,50,15];[m,n] size(a);d zeros(m); d mandist(a); % mandist 求矩阵列向量组之间的两两…

(二)JSX基础

什么是JSX 概念&#xff1a;JSX是JavaScript和XML&#xff08;HTML&#xff09;的缩写&#xff0c;表示在JS代码中编写HTML模版结构&#xff0c;它是React中编写UI模板的方式。 优势&#xff1a;1.HTML的声明式模版方法&#xff1b;2.JS的可编程能力 JSX的本质 JSX并不是标准…

python 判断点和线段相交

python 判断点和线段相交 import numpy as np import cv2 import numpy as npdef point_to_line_distance(points, line_segments):# line_segments [[549, 303], [580, 303]]# points [565, 304]x0, y0, x1, y1line_segments[0][0], line_segments[0][1], line_segments[1]…
最新文章