[PATCH v4] ungetc: Guarantee single char pushback

Maciej W. Rozycki macro@redhat.com
Thu Dec 12 12:16:23 GMT 2024


On Wed, 11 Dec 2024, Siddhesh Poyarekar wrote:

> > > -  int _flags2;
> > > +  int _flags2:24;
> > > +  char _short_backupbuf[1];
> > 
> > This doesn't create a 3-byte flags2, if that's what you're trying.
> > The underlying storage will still be int-sized, now with 8 unallocated bits.
> 
> gcc and clang both appear to pack in the struct just fine, which effectively
> gives flags2 3-bytes storage and _short_backupbuf right next to it.  Maybe
> I've misunderstood the issue you're trying to point out, could you please
> elaborate?

 Indeed a bit-field does get packed with an eligible adjacent non-bitfield 
member of the structure, although ISO C defers storage unit allocation to 
the implementation and therefore I do believe it is down to the individual 
platform-specific ABI.

 Then e.g. the o32 MIPS ABI has this clause[1]:

"* Bit-fields can share a storage unit with other struct/union members,
   including members that are not bit-fields.  Of course, struct members
   occupy different parts of the storage unit."

and the updated structure is laid out accordingly:

struct _IO_FILE {
	int                        _flags;               /*     0     4 */
	char *                     _IO_read_ptr;         /*     4     4 */
	char *                     _IO_read_end;         /*     8     4 */
	char *                     _IO_read_base;        /*    12     4 */
	char *                     _IO_write_base;       /*    16     4 */
	char *                     _IO_write_ptr;        /*    20     4 */
	char *                     _IO_write_end;        /*    24     4 */
	char *                     _IO_buf_base;         /*    28     4 */
	char *                     _IO_buf_end;          /*    32     4 */
	char *                     _IO_save_base;        /*    36     4 */
	char *                     _IO_backup_base;      /*    40     4 */
	char *                     _IO_save_end;         /*    44     4 */
	struct _IO_marker *        _markers;             /*    48     4 */
	struct _IO_FILE *          _chain;               /*    52     4 */
	int                        _fileno;              /*    56     4 */

	/* XXX 3 bytes hole, try to pack */
	/* Bitfield combined with previous fields */

	static int                        _flags2        /*     0: 0  0 */
	char                       _short_backupbuf[1];  /*    63     1 */
	__off_t                    _old_offset;          /*    64     4 */
	short unsigned int         _cur_column;          /*    68     2 */
	signed char                _vtable_offset;       /*    70     1 */
	char                       _shortbuf[1];         /*    71     1 */
	_IO_lock_t *               _lock;                /*    72     4 */

	/* size: 76, cachelines: 1, members: 21, static members: 1 */
	/* sum members: 85, holes: 1, sum holes: 3 */
	/* last cacheline: 76 bytes */

	/* BRAIN FART ALERT! 76 != 85 + 3(holes), diff = -12 */

};

(although the tool does seem confused a little here).

 AFAICT from `place_field' in gcc/stor-layout.cc it is the same across all 
the !TARGET_MS_BITFIELD_LAYOUT_P ABIs GCC supports, there's no provision 
for a per-target variation.

  Maciej



More information about the Libc-alpha mailing list