Repository navigation
Conversation
casaroli
requested review from
GUIDINGLI,
anchao,
masayuki2009,
pussuw and
xiaoxiang781216
as code owners
October 30, 2026 07:00
|
…eap. In the kernel build a vfork() child is in the address environment of its parent. group_allocate() and env_dup() put the task information and the environment of the child in the user heap of the parent, because that is the heap of the current address environment. When the child ends, task_uninit_info() returns at once for an unprivileged group, because the user heap of the group goes away with its address environment. The heap of a vfork() child is the heap of its parent, and it stays. Thus each vfork() lost these blocks in the heap of the parent. A shell runs each command with vfork(), so its heap grew with each command. Add GROUP_FLAG_VFORK. nxtask_setup_fork() sets it when a vfork() child joins the address environment of its parent. task_uninit_info() frees the task information and the environment of a group with this flag. group_leave() clears the flag when the address environment of the caller is not the one of the child (another process ends the child): a free from there goes into the heap of the caller. Then the blocks stay in the heap of the parent, as before. Flat and protected builds do not change: only CONFIG_ARCH_ADDRENV sets the flag, and only CONFIG_BUILD_KERNEL uses it. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
casaroli
force-pushed
the
fb-vfork-user-heap-up
branch
from
November 4, 2026 22:57
3d406a7 to
26ca3c8
Compare
Contributor
Author
|
This PR is split to make the review easier. Review order:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
In the kernel build a
vfork()child is in the address environment of its parent.nxtask_setup_fork()allocates the stack of the child (up_create_stack()), its task information (group_allocate()) and the copy of its environment (env_dup()) in the user heap of the current address environment: the heap of the parent. When the child ends (_exit(), orexec()and then_exit(0)inexecve()), its group ends, and the kernel-build exit code assumes that the user heap of the group goes away with its address environment. For avfork()child that is not true: the heap is the heap of the parent, and it stays. So eachvfork()lost the task information and the environment of the child (1288 bytes on qemu-armv8a:knsh) in the heap of the parent. A shell that runs each command withvfork()grows with each command.A new group flag,
GROUP_FLAG_VFORK(bit 7 oftg_flags, which was free), is set bynxtask_setup_fork()when avfork()child joins the address environment of its parent.task_uninit_info()then frees the task information and the environment of the child.group_leave()clears the flag when the caller is not in the address environment of the child (code in another process ends the child): a free from there would go into the heap of the caller, so the blocks stay in the heap of the parent, as before.Impact
vfork()no longer loses memory in the heap of the parent.vfork()child that code in another process ends (task_delete()from the kernel, for example) still leaves its blocks in the heap of the parent, as before. A child that ends itself (also by a fatal signal) frees them.CONFIG_ARCH_ADDRENVsets the flag, and onlyCONFIG_BUILD_KERNELcode uses it. No architecture code.tg_flagsis kernel-internal). Not a breaking change.Testing
Test program
forkstress.c: N rounds of a case, then the page pool and the kernel heap (/proc/meminfo), the processes in/proc, the lowest free file descriptor and the heap of the test (mallinfo()) are compared with the values after the first round. Cases:fork()+_exit();fork()+exec(); two children joined by a pipe; the same in a forked child;posix_spawn();vfork()+_exit();vfork()+exec().qemu-armv8a:knsh (QEMU, HVF) with
CONFIG_PIPES,CONFIG_SCHED_WAITPID,CONFIG_SCHED_CHILD_STATUS, on master 6b9b216:rv-virt:knsh64 (QEMU TCG), the same options: master vexec 200 +177624 bytes, vfork 100 +88800 (888 per child); this PR +0 in both. ostest exits with status 0 on master and with this PR.
ostest exits with status 0 on qemu-armv8a:knsh on master and with this PR, and on qemu-armv8a:nsh with this PR.
Builds with
EXTRAFLAGS="-Wno-cpp -Werror", each OK and withgroup_leave.ccompiled: qemu-armv8a:knsh, qemu-armv8a:nsh (arm64 kernel, flat), rv-virt:knsh64, rv-virt:pnsh64 (rv64 kernel, protected), mps2-an500:knsh (Cortex-M protected), sim:nsh.tools/checkpatch.sh -c -u -m -gpasses.