ostest's "vfork" test was never testing vfork(). It has the child write a
global and the parent observe the write -- the defining property of *sharing*,
not of vfork(), whose defining property is that the parent is suspended and
whose contract forbids the child to write anything at all. It passed because
NuttX implemented fork() and vfork() as the same sharing primitive, which
apache/nuttx#19562 separates.
vfork.c is rewritten to test what vfork() promises. The child does only what
POSIX permits -- it calls _exit(42) and nothing else, not even exit(), which
would run atexit handlers and flush stdio in the parent's address space. Since
the child may not write memory and the parent cannot run while the child lives,
the observable is the child's exit status: had the parent not been suspended,
it would have reached waitpid() while the child was still alive. Where child
status is not retained -- ostest_main() sets SA_NOCLDWAIT for the whole run,
deliberately -- ECHILD is accepted as equally good evidence, since it says the
child was already gone when the parent asked.
fork.c is new and tests POSIX fork(): the child's writes to .data, .bss and
the heap are invisible to the parent and vice versa, a pointer to a stack local
taken before the fork names the same object in both, and the child does
everything a vfork() child may not -- calls malloc() and printf(), and returns
from the function that called fork().
Both run at the top of user_main(). They exercise the lowest-level machinery
in the suite -- address environments, stack setup, the architecture's register
context -- so a fault in one takes the process down instead of reporting a
failure. Learning that in seconds rather than after everything else has passed
matters when a port is being brought up.
Each test gates on the one primitive it tests, ARCH_HAVE_VFORK and
ARCH_HAVE_FORK respectively. There is no compatibility layer and no mapping
between symbols. vfork.c no longer requires SCHED_WAITPID: the suspension is
in the kernel primitive now, so the test's core assertion holds without it and
only the status check is conditional.
The simulator is the one exception. It selects ARCH_HAVE_VFORK, but ostest
takes the sim down as soon as the test runs there, so the call keeps the
!ARCH_SIM guard that apps ee7642793 put on the old test in 2024. The old gate
hid this: ARCH_HAVE_FORK is not set on the sim, so the test was not built
there at all.
The other in-tree callers are audited for which primitive they actually meant:
* interpreters/python's _posixsubprocess and netutils/libwebsockets'
LWS_HAVE_WORKING_VFORK want the fork-then-exec path -- ARCH_HAVE_VFORK.
* python's os.fork() and libwebsockets' LWS_HAVE_FORK mean real fork() and stay
on ARCH_HAVE_FORK, so they become *absent* rather than silently wrong.
* testing/fs/fdsantest's vfork case follows ARCH_HAVE_VFORK.
interpreters/bas is deliberately left alone. Its SHELL and EDIT statements
reach for vfork() under an ARCH_HAVE_FORK guard and want the same treatment,
but checkpatch.sh checks the whole of any file a patch touches and
bas_statement.c produces 1681 pre-existing findings against master, so a
one-line change there fails CI on its own. The consequence is small:
EXAMPLES_BAS_SHELL is EXPERIMENTAL and already depends on ARCH_HAVE_FORK, so it
becomes unselectable rather than misbehaving.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Both the demo and the test asserted that each running instance of a module
gets its own copy of a library named in DT_NEEDED: two instances adding
their own seed each saw a total of seed*3.
That was true of the loader that walked DT_NEEDED itself. The loader now
hands the work to dlopen(), which returns the object already in the module
registry rather than loading a second copy of it, so there is one library
and one set of its globals, shared by every module that names it. The
module's own data stays private per instance, because exec() loads the
module afresh each time.
What an instance can still assert on its own is that every add it made
landed in the library, so that is what it checks; the totals interleave and
the final one counts both. The test additionally checks the consequences:
the library is pinned once rather than once per instance, and its
destructor runs once, at the last close, holding what both instances built
up.
USER_FAIL_PRIVATE becomes USER_FAIL_SHARED rather than gaining a
companion. The bit is a private protocol between cxxuser.cpp, which sets
it, and testing/fs/xipfs, which reads it; nothing else names it, and the
property it used to report no longer exists.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Adds two sections to the xipfs suite, guarded by CONFIG_FDPIC so a build
without the loader is unaffected. They belong here rather than in their own
test because what they exercise is modules loaded *out of the filesystem* --
the pin, the in-place mapping and the loader are one path.
'fdpic' asserts on the loader properties that otherwise fail *quietly*: a
loader that skips DT_INIT_ARRAY runs a C++ module happily with every global
left zero, one that skips DT_JMPREL loads a module that hard-faults only
once it calls out, and one that mis-sizes the descriptor pool corrupts the
heap. None of those announce themselves. The module exit status is the
channel -- each module checks its own invariants and reports a bitmask. It
also covers shared libraries across concurrent instances, per-instance data,
the leaf-library GOT fallback, the R_ARM_FUNCDESC descriptor pool, and every
firmware entry point that has to resolve a module callback, including
mq_notify and timer_create with SIGEV_THREAD.
'reject' mutates a known-good module byte by byte and asserts the loader
refuses it rather than loading something broken: a missing import, and more
DT_NEEDED entries than the walk will follow.
The modules are embedded as headers, for the same reason as in
examples/fdpicxip, and built for cortex-m3 for the same reason: one set of
blobs then runs on both the v7-M and v8-M targets. Their sources and the
makefile that regenerates these headers live in
apps/examples/fdpicxip/modules, so the copies the two apps carry are built
from the same sources in the same way.
Verified on a Pimoroni Pico Plus 2: fdpic 33/33, reject 7/7, and the whole
suite 130/130 with them included. The same three numbers on mps2-an500 under
QEMU, which is a Cortex-M7 rather than the RP2350's Cortex-M33.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Twelve sections, selected by name on the command line because the power loss
sweeps run for minutes while everything else runs in seconds.
The routine part covers the VFS paths, the write-once rules (reopen for
write, append, seek during write, truncate of a written file are all refused)
and both mmap variants: that a plain mapping lands inside the media window
with no heap growth, that MAP_XIP_STRICT fails with ENXIO rather than
copying, and that N mappings of one file produce N pins on one extent.
The rest is aimed at the two properties that are easy to get wrong and quiet
when they are:
Pin release. A pin taken by one task and a task that dies with a mapping
still live both have to end with the extent movable again -- the second
without the task ever calling munmap, since a module that faults never will.
Both are checked by asking the defragmenter to move the extent afterwards.
Power-loss atomicity. With CONFIG_FS_XIPFS_FAULT_INJECT the suite fails the
Nth flash operation, remounts, and checks the volume is consistent and every
file that had been committed is byte-for-byte intact. It sweeps N across
create, unlink and defragmentation, and repeats the sweep with the failing
write torn -- a partial program rather than a clean refusal -- which is what
a real power loss mid-program leaves behind.
Assisted-by: Claude Code:claude-opus-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
Add missing mode arguments to direct open() calls that use O_CREAT.
Also open the lp503x device with explicit read-only flags instead of O_CREAT, matching the device-node usage.
Signed-off-by: Nightt <87569709+nightt5879@users.noreply.github.com>
The matching nuttx commit removes CONFIG_HAVE_LONG_LONG; clean up the
remaining users in nuttx-apps so that "long long" is always assumed:
- examples/noteprintf, examples/nxscope:
unconditionally exercise the %lld / long long branch.
- fsutils/mkfatfs/configfat.c:
drop the 32-bit fall-back paths in mkfatfs_nfatsect12/16/32;
always use uint64_t for the FAT-size arithmetic.
- logging/nxscope/nxscope_chan.c:
drop the CONFIG_HAVE_LONG_LONG guard around the 64-bit
sample helpers.
- netutils/ftpd, netutils/ntpclient:
always emit the 64-bit format strings.
- testing/fs/fstest/fstest_main.c:
drop the parallel 32-bit verification path; keep only the
64-bit (long long) random pattern generator.
- system/zmodem/host/nuttx/compiler.h:
remove the host-side CONFIG_HAVE_LONG_LONG stub macro.
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
Replace app-side includes of <debug.h> with <nuttx/debug.h> to use the
header from the NuttX tree explicitly after the header move.
Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
change nvs module testcase name TESTING_MTD_CONFIG_FAIL_SAFE
to TESTING_MTD_CONFIG_NVS and modify the configuration names
related to mtdconfig testing.
Signed-off-by: zhaoxingyu1 <zhaoxingyu1@xiaomi.com>