Hello,

I want to discuss a breaking change before I open the pull requests, as
CONTRIBUTING.md 1.13 asks.

The problem

NuttX added fopencookie() in 12.4.0 (#10602). The function comes from
glibc. In glibc and in musl, the seek function of cookie_io_functions_t
returns int: 0 on success, with the new offset stored in *offset, or -1 on
failure:

https://man7.org/linux/man-pages/man3/fopencookie.3.html

In NuttX, cookie_seek_function_t returns off_t, and ftello() uses the
return value as the position. So a seek function written for glibc or musl:

- does not compile where off_t is not int: for example on 32-bit Arm
(int32_t is long there), and with CONFIG_FS_LARGEFILE. GCC 13 warns
(incompatible pointer type); GCC 14 and later stop with an error. libbsd's
funopen.c is such a function.
- compiles where off_t is int (arm64 without CONFIG_FS_LARGEFILE). But if
it returns 0 on success, as the glibc documentation asks, ftell() returns 0
after fseek(), because the position comes from the return value.

The proposal

1. nuttx: cookie_seek_function_t returns int. ftello() takes the position
from *offset, and fseeko() fails when the result is negative. The seek
functions of fmemopen() and open_memstream() return 0 (they already store
the offset in *offset).
2. nuttx-apps: testing/libc/fopencookie returns 0 from its seek function.

The two pull requests must merge together.

What breaks

- A seek function written for the NuttX type (an off_t result) gets the
same warning or error as above, in the other direction. Quick fix: change
the return type to int, store the new offset in *offset, and return 0 on
success, or -1 with errno set on failure.
- In nuttx and nuttx-apps, only testing/libc/fopencookie has such a
function. The seek functions of fmemopen(), open_memstream() and popen() in
libc change in the same commit. libtinycbor passes no seek function. I did
not search the code that nuttx-apps downloads at build time.

Alternatives

1. Keep the off_t type, and change only ftello() to take the position from
*offset. Then the NuttX seek functions still work, but code written for
glibc still does not compile where off_t is not int. A cast makes it
compile, but then the program calls the function through the wrong type,
which is undefined behaviour in C. So ported code still needs a
NuttX-specific change.
2. A Kconfig option that selects the glibc type, off by default. Then the
type of a public typedef depends on the configuration, and a library that
uses fopencookie() works only in the configurations that set the option.

Tests so far

QEMU, qemu-armv8a:knsh (kernel build), with a test program that has a
glibc-style seek function: on master, ftell() gives 0 after fseek(f, 6,
SEEK_SET) and after fseek(f, 0, SEEK_END); with the change it gives 6 and
11. ftell() on fmemopen() and open_memstream() streams is right before and
after. testing/libc/fopencookie passes on master and with the change.
ostest passes on qemu-armv8a:knsh and qemu-armv8a:nsh. stm32f4discovery:nsh
(flat) and lm3s6965-ek:qemu-protected (protected) build. Before a vote, I
will add build and ostest logs from real hardware of more than one
architecture, as CONTRIBUTING.md 1.14 requires.

Question

Do you agree with the change, or do you prefer one of the alternatives?

Thank you,
Marco Casaroli

Reply via email to