0.7.0 — adopt openkal 0.9, and make the aarch64 leg work for the first time - #18
Merged
Conversation
…d per implementation
Every report becomes an operation, so an implementation reports what is true of
the resource the caller named rather than one word for the whole machine. The
change that has teeth is `kal_fs_props`:
* it took no argument and claimed KAL_FS_PROP_CASE_SENSITIVE unconditionally.
This implementation offers the whole filesystem as a preopen, so a FAT
volume mounted anywhere on the machine is reachable through it, and the
claim is false there. It now consults the format the resource is on;
* it never claimed KAL_FS_PROP_LINKS while every operation here met them.
⚠️ AND ASKING NOW RESOLVES A LINK, BECAUSE OPENING ALWAYS DID.
`kal_fs_info` passed AT_SYMLINK_NOFOLLOW always while `kal_fs_open` did not set
O_NOFOLLOW --- the constant was declared in sys.h and used nowhere. So in one
program, opening a name reached a file and asking about it reported a link. A C
library above this reported `is_regular_file` as false for a name whose bytes it
could read, and one such node made a whole tree uncopyable.
The rest follows the specification:
* transfers return one signed word;
* `kal_env_*` and `kal_fs_preopen` and `kal_fs_list_next` copy into the
caller's buffer and report the length the value has;
* `kal_node_info` carries its own size, reports what was filled, and carries
the device and inode as an opaque identity a caller may compare and not
read --- which is what stops two different files reading as one;
* `kal_fs_link_create` and `kal_fs_link_read` over symlinkat and readlinkat,
with availability answered by the enquiry before they are called;
* `kal_memory_granularity` from the auxiliary vector rather than a constant;
* `kal_fs_max_name`, because a bound a caller cannot learn produces a failure
it cannot attribute --- a longer name was refused as `kal_err_invalid`,
which is also the answer for a name that ascends;
* `kal_fs_stream` and `kal_spawn_streams` carry their type;
* `kal_version` and `kal_interfaces`, answered with constants.
168 conformance observations hold, up from 143.
… a kind Two defects, both from one habit: a constant that differs between architectures written once, as though it did not.⚠️ ⚠️ THE OPEN FLAGS. `O_DIRECTORY`, `O_NOFOLLOW` and `O_DIRECT` have one set of values on x86_64 and another in the kernel's architecture-independent header, which is what aarch64 uses: x86_64 aarch64 O_DIRECTORY 0200000 040000 O_NOFOLLOW 0400000 0100000 O_DIRECT 040000 0200000 So on aarch64 this asked for O_DIRECT where it meant O_DIRECTORY, and the kernel refuses O_DIRECT on a directory. EVERY DIRECTORY FAILED TO OPEN --- including the two preopens supplied at inception, which are every directory a program above this can reach. Measured: `kal_fs_preopen_count' answered two and both entries reported `kal_err_permission' with a handle of zero. A C library above then had nothing to resolve a name against, so every `open' answered ENOENT and `getcwd' answered "/", which reads as a program started somewhere odd rather than as an implementation that opened nothing.⚠️ ⚠️ THE STAT RECORD. The kernel's architecture-independent `struct stat' places the mode immediately after the device and inode; the layout here was neither that nor x86_64's. The mode was read from offset 60, where the kernel writes a group, and the size from 32, where it writes a device number. Measured, the same program on both: x86_64 file: kind=1 size=10 writable=1 link: kind=3 aarch64 file: kind=4 size=0 writable=0 link: kind=4 Every node on aarch64 was "some other kind of thing", of length zero and not writable --- so a C library reported that a file it had just written ten bytes to was not a regular file, and every operation that decides upon a kind decided wrongly. ⭐ THE OFFSETS ARE NOW ASSERTED. A field read from the wrong offset is a wrong answer and not a failure, so the build could not report it; now it can.⚠️ AND NOTHING IN THIS ECOSYSTEM COULD HAVE CAUGHT EITHER. The conformance suite runs on the machine that builds it, and every hosted machine in this ecosystem's continuous integration is x86_64 or an arm64 Mac --- which uses openkal-macos and a different record again. The aarch64 leg of this implementation was built and never run. Both were found by running it: under qemu-aarch64 the port's own POSIX probe reported seven failures where x86_64 reported none, and after these two it reports one, which is the emulator's own handling of a program that starts another.
⚠️ THE TESTS WERE NOT UPDATED AND CI IS WHERE THAT SHOWED. Seven of them use the surface directly and every one of them failed to compile against 0.9 --- which is the arrangement working: a package that changes an interface and does not change what examines it has changed nothing that anybody checked. One of them then failed at RUN rather than at compile, and the reason is worth recording: the enquiry that reports a preopen's name now copies it into the caller's buffer, so a call site that passed a null buffer and then read the name compiled and dereferenced zero. The end of an enumeration is likewise the iterator becoming zero rather than a pointer becoming null, because there is no pointer any more.⚠️ ⚠️ AND THE README TOLD A READER TO ASK FOR A VERSION FOUR MINOR RELEASES OLD. Every README here opens by showing what a program writes in its manifest, which is the first thing a reader copies and the last thing anyone edits. The specification's own said `openkal = "0.5.1"` while the package was at 0.9.0. ⭐ The staleness is not the finding. That it was INVISIBLE is: the surface is checked against SURFACE.txt, the declarations against both forms, the behaviour against the conformance suite --- and the one line a reader actually types was checked by nobody. `tools/check-readme-versions.sh` in the specification's repository now checks it, and reports `?` rather than passing where it cannot look, so its "no" and its "did not run" do not read the same. 7 passed, 0 failed.
…es not
glibc calls every .init_array entry with (argc, argv, envp). musl calls them
with NO ARGUMENTS. src/env.cpp declared a constructor taking three and recorded
what arrived, which under musl is whatever the argument registers happened to
hold -- so every program above this implementation and a musl C library was told
its argument count was a text address, and the first enquiry after the count
dereferenced a small integer as a pointer.
Found by running this package's tests for aarch64, where it reads as an
architecture defect. It is not, and the control that separates the two is
x86_64-linux-musl:
target argc argv envp
x86_64-linux-gnu 1 <stack> <stack>
x86_64-linux-musl 0x4004c2 1 <stack>
aarch64-linux-musl 0x405ee4 1 <stack>
Both musl rows are shifted by one and the glibc row is not, so the axis is the C
library and not the machine. Running only aarch64 would have attributed it to
the machine, and the fix would have been wrong.
The arguments are now checked rather than believed -- argv[argc] must be the
terminator, argc must be a count -- and where they do not hold the vectors are
recovered from `environ' by walking back over argv's terminator to the slot that
holds the count, which must equal the number of entries actually found. Where
even that does not hold, nothing is recorded and the program is told it has no
arguments, which is an answer rather than a fault.
`environ' is a WEAK reference and the independence check now says so as a rule
rather than as an exception: this one name is permitted only when its type
letter is weak. It is admissible where `puts' is not because a call into the
runtime a program supplied can re-enter this implementation without bound and a
pointer executes nothing, and because weak means a program with no C library
still links. A strong reference to the same name would make one required
silently, and the check now fails on it -- measured, both ways.
Verified: 7 tests pass on x86_64-linux-gnu, x86_64-linux-musl and
aarch64-linux-musl.
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.
Adopts openkal 0.9, and fixes two defects that meant the aarch64 leg of this
implementation had never worked. Both were found by running it; neither could
have been found by building it.
The open flags.
O_DIRECTORY,O_NOFOLLOWandO_DIRECThave one set ofvalues on x86_64 and another in the kernel's architecture-independent header,
which is what aarch64 uses:
O_DIRECTORYO_NOFOLLOWO_DIRECTSo on aarch64 this asked for
O_DIRECTwhere it meantO_DIRECTORY, and thekernel refuses
O_DIRECTon a directory. Every directory failed to open —including the two preopens supplied at inception, which are every directory a
program above this can reach. Measured:
kal_fs_preopen_countanswered two andboth entries reported
kal_err_permissionwith a handle of zero. A C libraryabove then had nothing to resolve a name against, so every
openansweredENOENTandgetcwdanswered/— which reads as a program started somewhereodd rather than as an implementation that opened nothing.
The stat record. The kernel's architecture-independent
struct statplacesthe mode immediately after the device and inode; the layout here was neither that
nor x86_64's. The mode was read from offset 60, where the kernel writes a group,
and the size from 32, where it writes a device number. The same program on both:
Every node on aarch64 was "some other kind of thing", of length zero and not
writable — so a C library reported that a file it had just written ten bytes to
was not a regular file, and every operation that decides upon a kind decided
wrongly. ⭐ The offsets are now asserted: a field read from the wrong offset
is a wrong answer and not a failure, so the build could not report it; now it can.
on the machine that builds it, and every hosted machine in CI is x86_64 or an
arm64 Mac — which uses openkal-macos and a different record again. The aarch64
leg was built and never run.
openkal 0.9
kal_fs_propstakes the directory and consults the format the volume is. It tookno argument and claimed
KAL_FS_PROP_CASE_SENSITIVEunconditionally — false onany machine with a FAT volume mounted, which this implementation makes reachable
because it offers the whole filesystem as a preopen — and it never claimed
KAL_FS_PROP_LINKSwhile every operation here met them.kal_fs_infopassed
AT_SYMLINK_NOFOLLOWalways whilekal_fs_opendid not setO_NOFOLLOW— the constant was declared in
sys.hand used nowhere. So in one program,opening a name reached a file and asking about it reported a link.
Also: transfers return one signed word; values are copied into the caller's
buffer;
kal_node_infocarries its own size, what was filled, and the device andinode as an opaque identity;
kal_fs_link_create/kal_fs_link_readoversymlinkat/readlinkat;kal_memory_granularityfrom the auxiliary vector;kal_fs_max_name; typed stream handles;kal_versionandkal_interfaces.Conformance: 168 observations hold, up from 143. Surface: 95/95 on both
x86_64 and aarch64.