nuttx/libs/libc
Marco Casaroli b7faaed58f libc, sched: Resolve FDPIC descriptors at module callback entry points.
A module's function pointer is the address of a two-word descriptor in its
writable segment, not a code address.  Firmware that accepts one, stores it,
and later branches to it therefore jumps into the module's RAM data.  There
is no diagnostic: the board takes a HardFault with a dead console.

qsort and bsearch have resolved the descriptor since FDPIC support landed.
Nothing else did, and nothing noticed, because qsort's comparison function
was the only callback anything exercised.  That left every other entry point
looking perfectly usable -- a module could call one, it would return success,
and the fault arrived later from somewhere else.  Resolution is opt-in per
call site via fdpic_callback(), and this covers the rest of them:
pthread_create, signal, task_create, pthread_once, task_spawn, scandir and
sigaction.

Resolution happens once, in the innermost routine the paths share, for the
reason qsort already documents: resolving twice would treat a code address as
a descriptor.  task_create_with_stack resolves and task_create forwards to
it; nxsig_action() resolves for both signal() and a direct sigaction(), on
the local copy it already makes, so the caller's const struct is untouched
and the SA_SIGINFO form is covered through the union.

Two entry points need care beyond that pattern:

signal() has to exclude the dispositions by hand.  SIG_IGN, SIG_DFL, SIG_HOLD
and SIG_ERR are the integers 0, 1, 2 and -1 rather than addresses, and
fdpic_callback() declines to dereference NULL and nothing else -- handing it
SIG_ERR would read through (void *)-1.

scandir takes two pointers.  Its filter is called by scandir itself and is
resolved here; its comparison function is handed to qsort(), whose own entry
point resolves it, so resolving it here as well would resolve twice.  The
test passes both at once, which is what exercises that distinction.

Resolving the code address is sufficient at all of these.  A thread or task
created from a module inherits its D-Space -- nxtask_dup_dspace() runs before
up_initial_state() installs it in the FDPIC register -- and a signal handler
or pthread_once init routine runs in a context that already holds the
module's data base.

Verified on an RP2350 with a module that hands its own function to each entry
point.  Each assertion was also checked against a deliberate breakage:
removing the scandir filter resolution, and adding a second resolution of the
comparison function, each take the board down with a HardFault rather than
printing a FAIL line -- which is how a broken callback resolution manifests on
Cortex-M, and confirms the assertions test what they name.

mq_notify and timer_create with SIGEV_THREAD remain, and are harder: their
callback runs on a work-queue worker that carries no module data base at all.

Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
2026-08-01 12:23:27 +02:00
..
aio include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
assert lib_stackchk.c: a duplicate implementation error reported during compilation 2026-02-02 13:22:07 +08:00
audio include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
builtin libc/builtin: support per-application priority/stacksize under KERNEL build. 2026-07-13 15:23:39 -03:00
ctype style: fix spelling in code comments and strings 2025-05-23 10:48:41 +08:00
dirent libc, sched: Resolve FDPIC descriptors at module callback entry points. 2026-08-01 12:23:27 +02:00
dlfcn include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
elf libelf:support find symbol by symbol name 2026-07-15 12:24:44 -03:00
errno
eventfd
fdt libs/libc/fdt/Make.defs: cannot move due to directory not empty bugfix 2024-10-09 15:42:17 +08:00
fixedmath !compiler: drop CONFIG_HAVE_LONG_LONG and require long long support 2026-05-19 16:21:28 +08:00
gdbstub arch/arm64: fix backtrace register access and gdbstub config guard 2026-01-16 08:55:47 -03:00
gnssutils libc: remove reference to non-existent readme 2025-10-11 17:07:51 -04:00
grp libc/grp: add getgrouplist() 2026-06-23 23:09:22 +08:00
hex2bin include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
inttypes !compiler: drop CONFIG_HAVE_LONG_LONG and require long long support 2026-05-19 16:21:28 +08:00
libgen
locale style/FAR: remove FAR qualifier 2025-11-10 10:56:29 +01:00
lzf !compiler: drop CONFIG_HAVE_LONG_LONG and require long long support 2026-05-19 16:21:28 +08:00
machine arch/tricore: Full implementation of setjmp and longjmp. 2026-05-22 00:38:02 +08:00
misc libc/crc32: add IEEE-compatible crc32_ieee for Linux/zlib interop 2026-07-03 10:18:28 +08:00
net include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
netdb netdb: Add http and https service entries 2026-07-23 15:34:02 +08:00
obstack include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
pthread libc, sched: Resolve FDPIC descriptors at module callback entry points. 2026-08-01 12:23:27 +02:00
pwd libc/pwd: default ostest multiuser passwd path to /tmp/ostest_passwd 2026-07-30 09:48:10 +08:00
queue
regex libs/libc/regex: remove logically dead code in regcomp.c 2026-01-24 19:28:56 +08:00
sched include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
search libc/search: add foreach api for hcreate_data 2025-12-25 09:39:03 +08:00
semaphore pthread: move pthread_cond to userspace 2026-01-26 16:26:39 +08:00
signal libc, sched: Resolve FDPIC descriptors at module callback entry points. 2026-08-01 12:23:27 +02:00
spawn spawn: allow zero stacksize/priority to use binary loader defaults 2026-07-15 12:24:44 -03:00
stdio !include/fcntl.h: align open flags with Linux values 2026-06-30 13:43:44 +08:00
stdlib binfmt/fdpic: Add an FDPIC ELF module loader. 2026-08-01 12:23:27 +02:00
stream libc/stream: Check lowout bounds before access 2026-07-06 09:02:22 +02:00
string !compiler: drop CONFIG_HAVE_LONG_LONG and require long long support 2026-05-19 16:21:28 +08:00
symtab include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
syslog drivers/syslog: Add RFC 5424 protocol support 2025-06-13 20:26:57 +08:00
termios drivers/serial: add job-control TTY ioctls and libc wrappers 2026-06-23 16:26:53 -03:00
time libc/time: Fix POSIX timezone string parsing. 2026-07-25 19:54:18 +08:00
tls libc/tls: update preprocessor condition comment to match implementation 2026-01-31 02:49:10 +08:00
uio move readv/writev to the kernel 2024-10-30 17:07:54 +08:00
unistd sched/group: add getresuid, getresgid, setreuid, and setregid 2026-07-30 09:48:10 +08:00
userfs include/debug.h: Move to include/nuttx/debug.h 2026-04-07 07:50:06 -03:00
uuid libc: Refine the arc4random_buf implementation 2024-10-26 18:04:21 -03:00
wchar style: fix spelling in code comments and strings 2025-05-23 10:48:41 +08:00
wctype
wqueue !sched/clock: remove CONFIG_SYSTEM_TIME64 and always use 64-bit time 2026-05-19 16:21:28 +08:00
zoneinfo tools: fix stale archive members surviving a Kconfig-driven CSRCS change 2026-07-28 21:26:03 -03:00
.gitignore libc/elf: rename modlib to libelf 2025-04-11 09:43:22 +08:00
CMakeLists.txt
Kconfig libc/elf: rename modlib to libelf 2025-04-11 09:43:22 +08:00
libc.csv !compiler: drop CONFIG_HAVE_LONG_LONG and require long long support 2026-05-19 16:21:28 +08:00
libc.h libc/machine:Add prefixes to libc functions implemented by arch 2024-10-31 18:11:16 +08:00
limits_check.c libs/libc: add limits checks 2026-07-02 09:02:21 -03:00
Makefile tools: fix stale archive members surviving a Kconfig-driven CSRCS change 2026-07-28 21:26:03 -03:00