Skip to content

0.8.0 — a replacement that failed is reported to the caller, not to nobody - #21

Merged
Sunrisepeak merged 1 commit into
mainfrom
spawn-reports-exec-failure
Aug 30, 2026
Merged

0.8.0 — a replacement that failed is reported to the caller, not to nobody#21
Sunrisepeak merged 1 commit into
mainfrom
spawn-reports-exec-failure

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

Closes #20.

⚠️⚠️ The replacement happens in the duplicate, so its failure had nowhere to go

A program is started here by duplicating this image and replacing the duplicate.
The replacement is the part that fails — the name is absent, is a directory, is
not a program, or may not be executed — and it failed inside an image the
caller does not have
. This implementation ended that image with 127 and
answered kal_ok with a handle, so a caller learned something was wrong only by
waiting and reading 127 — which is exactly what a program that ran and exited
127 reports.

What it cost, measured by a consumer rather than here. openkal-musl
expresses execve as starting a program and ending with its status, so a name
that could not be started ended the calling program with 127 instead of
returning -1. musl's execvp issues one execve per PATH entry and needs each
to return, so the search could not survive its first miss — bwrap, installed at
/usr/bin/bwrap, was reported as not installed. openkal-linux#13, nine of
nineteen test failures.

openkal-musl 0.10.0 answered the half it could, by asking kal_fs_info whether
the name is there. It cannot answer the other half: openkal reports no
execute permission, so "present and not a program" is invisible above this line.
It was never invisible here.

What it is

A pipe whose ends close when the image is replaced. Nothing arrives ⇒ the
replacement happened. A value arrives ⇒ it did not, and the value says why; this
image then waits for the duplicate so nothing is left for a caller to meet.

⚠️ The pipe must not sit where the duplicate is about to place something.
Streams go to 0–2 and granted directories to 3 upwards, so a pipe holding one of
those numbers would be closed by the very placement whose failure it exists to
report — and this image would read end-of-input and call that success.
F_DUPFD_CLOEXEC answers the lowest free descriptor at or above a bound, which
moves it aside without naming — and so without closing — a descriptor the caller
holds. dup3 cannot: it is told the number.

⭐ A pipe that cannot be made is not a reason to refuse a spawn.

Measured, with the released version as the control

A file that exists, is not a program, named to posix_spawn and execve through
openkal-musl:

0.7.1   spawn reported SUCCESS, child status 0x7f00, and the probe then died
        at 127 on the execve — two observations red and the rest unreached
here    refused with EACCES, and execve RETURNED with EACCES

nr_fcntl is added for both architectures and f_dupfd_cloexec beside
o_cloexec; nothing else in the surface changes.

… nobody

Closes #20.

⚠️⚠️ THE REPLACEMENT HAPPENS IN THE DUPLICATE, SO ITS FAILURE HAD NOWHERE TO GO.

A program is started here by duplicating this image and replacing the duplicate.
The replacement is the part that fails --- the name is absent, or is a directory,
or is not a program, or may not be executed --- and it failed inside an image the
caller does not have. This implementation ended that image with 127 and answered
`kal_ok' with a handle, so a caller learned something was wrong only by waiting
and reading 127, which is exactly what a program that RAN and exited 127 reports.

⭐ WHAT IT COST, MEASURED BY A CONSUMER RATHER THAN HERE. openkal-musl expresses
`execve' as starting a program and ending with its status, so a name that could
not be started ended the CALLING program with 127 instead of returning -1. musl's
`execvp' issues one `execve' per PATH entry and needs each to return, so the
search could not survive its first miss --- `bwrap', installed at /usr/bin/bwrap,
was reported as not installed. openkal-linux#13, nine of nineteen test failures.

openkal-musl 0.10.0 answered the half it could, by asking `kal_fs_info' whether
the name is there. It cannot answer the other half: openkal reports no execute
permission, so "present and not a program" is invisible above this line. It was
never invisible HERE --- the duplicate knows precisely why --- and this release is
the channel that carries it.

--- what it is -------------------------------------------------------------

A pipe whose ends close when the image is replaced. Nothing arrives ⇒ the
replacement happened. A value arrives ⇒ it did not, and the value says why; this
image then waits for the duplicate so nothing is left for a caller to meet.

⚠️ AND THE PIPE MUST NOT SIT WHERE THE DUPLICATE IS ABOUT TO PLACE SOMETHING.
Streams go to 0, 1 and 2 and granted directories to 3 upwards, so a pipe holding
one of those numbers would be closed by the very placement whose failure it
exists to report --- and this image would read end-of-input and call that success.
`F_DUPFD_CLOEXEC' answers the lowest FREE descriptor at or above a bound, which
is the primitive for moving it aside without NAMING --- and so without closing ---
a descriptor the caller holds. `dup3' cannot: it is told the number.

⭐ A pipe that cannot be made is not a reason to refuse a spawn. The channel is
an improvement on the answer that follows it, not a precondition of it.

--- measured, with the released version as the control ----------------------

A file that exists, is not a program, and is named to `posix_spawn' and `execve'
through openkal-musl:

    0.7.1   spawn reported SUCCESS, child status 0x7f00, and the probe then died
            at 127 on the execve --- two observations red and the rest unreached
    here    refused with EACCES, and execve RETURNED with EACCES

`nr_fcntl' is added for both architectures and `f_dupfd_cloexec' beside
`o_cloexec'; nothing else in the surface changes.
@Sunrisepeak
Sunrisepeak merged commit 3f16c78 into main Aug 30, 2026
2 checks passed
@Sunrisepeak
Sunrisepeak deleted the spawn-reports-exec-failure branch August 30, 2026 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

kal_process_spawn does not report an exec that failed, and the caller cannot find out

1 participant