open_memstream() ‒ NUL injected on seek/write that doesn't bump the size, I think it can't be per POSIX (and other implementations don't)

наб nabijaczleweli@nabijaczleweli.xyz
Wed Sep 18 21:31:45 GMT 2024


Hi!

I've found what I think is a discrepancy between glibc and POSIX,
and is definitely a difference between glibc and other libcs,
in how open_memstream() treats seeking into the middle.

Behold the test program:
	#include <stdio.h>
	int main() {
		char *dt;
		size_t s;
		FILE * f = open_memstream(&dt, &s);
1		fputs("gaming", f);
2		fputs("tereftalan", f);
3		fseek(f, 6, SEEK_SET);
4		fputc('Q', f);
		fclose(f);
		puts(dt);
		printf("%zu\n", s);
	}

This yields "gamingQereftalan", 7 on musl and the illumos gate,
        and "gamingQ",          7 on glibc.

POSIX.1-2024 defers to C, and says
51164  The stream shall maintain a current position in the allocated buffer and a current buffer length.
51165  The position shall be initially set to zero (the start of the buffer). Each write to the stream shall
51166  start at the current position and move this position by the number of successfully written bytes
51167  for open_memstream( )
51168                      The length shall be initially set to zero. If a write moves the position to a
51169  value larger than the current length, the current length shall be set to this position. In this case a
51170  null character for open_memstream( )                                                 shall be
51171  appended to the current buffer.                    The terminating null is not included in the
51172  calculation of the buffer length.

51173  After a successful fflush( ) or fclose( ), the pointer referenced by bufp shall contain the address of
51174  the buffer, and the variable pointed to by sizep shall contain the smaller of the current buffer
51175  length and the number of bytes for open_memstream( ),
51176                      between the beginning of the buffer and the current file position indicator.

51177  The fseek( ) and fseeko( ) functions can be used to set the file position beyond the current buffer
51178  length. [this example doesn't trigger this] 
51182                                                                     If fseek( ) or fseeko( ) is called
51183  with SEEK_END as the whence argument [this example doesn't]

Thus, if fflush(f) was called after:
  1: [dt, dt + s] = "gaming\0"
  2: [dt, dt + s] = "gamingtereftalan\0"
  3: [dt, dt + s] = "gamingt"
  4: [dt, dt + s] = "gamingQe"
because, per ll. 51168-51171,
only 1 and 2 move the cursor beyond the length.

Right?

Best,
наб
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20240918/e85380b1/attachment.sig>


More information about the Libc-alpha mailing list