From 433e9c48d0235eba41cdef2df85ee8dc1c18b139 Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 08:33:16 +0900 Subject: [PATCH 1/2] 0.17.1: KAL_SPAWN_ONE_STRING --- the vector joined as it is, where a program receives one string A program running a person's command through the command interpreter of an environment that passes one string could not give it the command: the quoting that recovers a vector put escapes the interpreter does not read into every command with a quotation mark (clause 7.6, entry 39). Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- README.md | 2 +- SPEC.md | 18 +++++++++++++++++- SURFACE.txt | 2 +- conformance/src/macros_reach.cpp | 2 ++ conformance/src/sections/process.cpp | 18 ++++++++++++++++++ include/openkal/process.h | 16 ++++++++++++++++ include/openkal/version.h | 2 +- mcpp.toml | 2 +- src/macros.cppm | 2 ++ src/process.cppm | 2 ++ 10 files changed, 61 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1855dfc..24e58bb 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ conditional on the target. ```toml [dependencies] -openkal = "0.17.0" +openkal = "0.17.1" [target.'cfg(os = "linux")'.dependencies] openkal-linux = "0.18.0" diff --git a/SPEC.md b/SPEC.md index 20c7bbd..942a80a 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1,4 +1,4 @@ -# openkal Specification, version 0.17 +# openkal Specification, version 0.17.1 ## 1. Scope @@ -799,6 +799,16 @@ belongs to the caller rather than to the implementation. An implementation whose environment has no argument vector shall report `kal_err_unsupported` from `kal_process_spawn` rather than discard the vector. +An environment that gives a started program one string, which the program splits +by rules of its own, passes the vector by quoting each element so that the +conventional splitting recovers it. A program whose rules are not the +convention --- the command interpreter, whose `/c` takes the rest of the string +as a command line of its own grammar --- cannot be given every argument through +that quoting. `KAL_SPAWN_ONE_STRING` asks for the first element quoted as usual +and the others joined after it by single spaces, unaltered; an implementation +claims it with `KAL_PROCESS_PROP_ONE_STRING`, and one whose environment gives a +program a vector reports `kal_err_not_supported` (version 0.17.1). + This rule was absent from version 0.3, and both implementations existing at the time prepended the path. They agreed only because they shared an author; a third implementer had nothing to consult. The defect was found by writing one program @@ -1673,6 +1683,12 @@ The following are recorded so that they are not mistaken for oversights. pending, so a program that ended a connection from another context waited for its reader there alone; the release of the connection is not the remedy, since a handle in use is not to be released (clause 7.2). +39. **A command interpreter's command line.** **Stated in 0.17.1**, clause 7.6, + with `KAL_SPAWN_ONE_STRING`. A program that ran a person's command through + the command interpreter of an environment that passes one string had no way + to give it the command: the quoting that recovers a vector put escapes the + interpreter does not read into every command that held a quotation mark, + which a path with a space in it does. ## 12. Images diff --git a/SURFACE.txt b/SURFACE.txt index 4261a5e..1654717 100644 --- a/SURFACE.txt +++ b/SURFACE.txt @@ -1,4 +1,4 @@ -# The C surface of openkal 0.17, one name per line. +# The C surface of openkal 0.17.1, one name per line. # # This file is normative and is the single source consulted by clause 9. A # conforming implementation exports the names of the interfaces it provides diff --git a/conformance/src/macros_reach.cpp b/conformance/src/macros_reach.cpp index 950b62a..73a27c8 100644 --- a/conformance/src/macros_reach.cpp +++ b/conformance/src/macros_reach.cpp @@ -39,5 +39,7 @@ static_assert(kal::macros::KAL_PROCESS_PROP_STOP_REQUESTED_M == 128u); // One from another interface, so that a generator which emitted only the last // header it read would be caught. static_assert(kal::macros::KAL_SPAWN_BOUND_LIFETIME_M == 1u); +static_assert(kal::macros::KAL_SPAWN_ONE_STRING_M == 2u); +static_assert(kal::macros::KAL_PROCESS_PROP_ONE_STRING_M == 512u); } // namespace diff --git a/conformance/src/sections/process.cpp b/conformance/src/sections/process.cpp index 88e9fd8..d858cc7 100644 --- a/conformance/src/sections/process.cpp +++ b/conformance/src/sections/process.cpp @@ -356,6 +356,24 @@ void run() { "the implementation claims prop_bound_lifetime"); } + // KAL_SPAWN_ONE_STRING (0.17.1): an environment that gives a program a + // vector, and so does not claim the position, refuses the request. + if ((kal_process_props() & kal::process::one_string.bits) == 0) { + kal_process p{}; + const char* argv[1] = { "x" }; + const kal_uintptr lens[1] = { 1 }; + const kal_spawn how{ kal::fs::working(), kal::fs::working(), nullptr, + nullptr, 0, kal::process::one_string_flag.bits }; + const int e = kal_process_spawn(&how, "x", 1, argv, lens, 1, + nullptr, nullptr, 0, nullptr, &p); + observe(kind::behaviour, e == kal_err_not_supported, + "a joined command line where programs receive vectors is refused"); + } else { + unobserved(kind::behaviour, + "a joined command line where programs receive vectors is refused", + "the implementation claims prop_one_string"); + } + // THE UNIT IS ASKED FOR BY A POINTER AND NOT BY A FLAG, so an // implementation that cannot form one refuses a NON-NULL `job' --- there // is no bit to set and none to test. diff --git a/include/openkal/process.h b/include/openkal/process.h index a5e41bc..003a8e8 100644 --- a/include/openkal/process.h +++ b/include/openkal/process.h @@ -83,6 +83,8 @@ struct kal_preopen { #define KAL_PROCESS_PROP_STOP_REQUESTED ((kal_uintptr)1u << 7) /* kal_process_open_id finds a program by its identifier. Version 0.17. */ #define KAL_PROCESS_PROP_OPEN_ID ((kal_uintptr)1u << 8) +/* KAL_SPAWN_ONE_STRING is answered here. Version 0.17.1. */ +#define KAL_PROCESS_PROP_ONE_STRING ((kal_uintptr)1u << 9) /* HOW A PROGRAM IS STARTED, AND IT IS ONE OPERATION BECAUSE 0.11 STOPPED * MAKING IT A FAMILY. @@ -219,6 +221,20 @@ struct kal_spawn { * program runs to completion, unsupervised. openkal-linux#13. */ #define KAL_SPAWN_BOUND_LIFETIME ((kal_uintptr)1u << 0) +/* THE VECTOR JOINED AS IT IS, WHERE A PROGRAM RECEIVES ONE STRING. Version + * 0.17.1, clause 7.6. + * + * An environment that gives a started program one string, which the program + * splits by rules of its own, ordinarily quotes each element so that the + * conventional splitting recovers the vector. A program whose rules are not the + * convention cannot be given every argument through that quoting: the command + * interpreter takes the rest of the string after `/c' as a command line of its + * own grammar, and a quoted element arrives with the quoting's escapes in it. + * With this flag the first element is quoted as usual and the others are joined + * after it by single spaces, as they are. An environment that gives a program a + * vector answers kal_err_not_supported: the request means nothing there. */ +#define KAL_SPAWN_ONE_STRING ((kal_uintptr)1u << 1) + /* A set of started programs that end together --- see `kal_spawn.job'. One * machine word, as every handle here is. */ struct kal_job { kal_uintptr h; }; diff --git a/include/openkal/version.h b/include/openkal/version.h index cb40c44..d9b18fd 100644 --- a/include/openkal/version.h +++ b/include/openkal/version.h @@ -43,7 +43,7 @@ * consumer actually asks for was checked by nobody. */ #define KAL_VERSION_MAJOR 0u #define KAL_VERSION_MINOR 17u -#define KAL_VERSION_PATCH 0u +#define KAL_VERSION_PATCH 1u #define KAL_VERSION_MAKE(major, minor, patch) \ (((kal_u64)(major) << 32) | ((kal_u64)(minor) << 16) | \ diff --git a/mcpp.toml b/mcpp.toml index 571dcee..4cee2cf 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -1,7 +1,7 @@ [package] namespace = "mcpplibs" name = "openkal" -version = "0.17.0" +version = "0.17.1" description = "openkal: a portable kernel ABI specification. This package carries the normative declarations; implementations are separate packages." license = "Apache-2.0" authors = ["mcpplibs"] diff --git a/src/macros.cppm b/src/macros.cppm index 1f64cf8..ea24705 100644 --- a/src/macros.cppm +++ b/src/macros.cppm @@ -91,6 +91,7 @@ inline constexpr kal_uintptr KAL_PROCESS_PROP_CHANNEL_M = (kal_uintptr)( inline constexpr kal_uintptr KAL_PROCESS_PROP_EXIT_STATUS_M = (kal_uintptr)(KAL_PROCESS_PROP_EXIT_STATUS); inline constexpr kal_uintptr KAL_PROCESS_PROP_GRANT_DIR_M = (kal_uintptr)(KAL_PROCESS_PROP_GRANT_DIR); inline constexpr kal_uintptr KAL_PROCESS_PROP_JOB_M = (kal_uintptr)(KAL_PROCESS_PROP_JOB); +inline constexpr kal_uintptr KAL_PROCESS_PROP_ONE_STRING_M = (kal_uintptr)(KAL_PROCESS_PROP_ONE_STRING); inline constexpr kal_uintptr KAL_PROCESS_PROP_OPEN_ID_M = (kal_uintptr)(KAL_PROCESS_PROP_OPEN_ID); inline constexpr kal_uintptr KAL_PROCESS_PROP_STOP_REQUESTED_M = (kal_uintptr)(KAL_PROCESS_PROP_STOP_REQUESTED); inline constexpr kal_uintptr KAL_PROCESS_PROP_STREAM_PASSING_M = (kal_uintptr)(KAL_PROCESS_PROP_STREAM_PASSING); @@ -107,6 +108,7 @@ inline constexpr kal_uintptr KAL_SHUT_WRITE_M = (kal_uintptr)( inline constexpr kal_uintptr KAL_SPACE_PROP_CLONE_HANDLES_M = (kal_uintptr)(KAL_SPACE_PROP_CLONE_HANDLES); inline constexpr kal_uintptr KAL_SPACE_PROP_DEFERRED_COPY_M = (kal_uintptr)(KAL_SPACE_PROP_DEFERRED_COPY); inline constexpr kal_uintptr KAL_SPAWN_BOUND_LIFETIME_M = (kal_uintptr)(KAL_SPAWN_BOUND_LIFETIME); +inline constexpr kal_uintptr KAL_SPAWN_ONE_STRING_M = (kal_uintptr)(KAL_SPAWN_ONE_STRING); inline constexpr kal_uintptr KAL_STREAM_PROP_INTERACTIVE_M = (kal_uintptr)(KAL_STREAM_PROP_INTERACTIVE); inline constexpr kal_uintptr KAL_TASK_PROP_PARALLEL_M = (kal_uintptr)(KAL_TASK_PROP_PARALLEL); inline constexpr kal_uintptr KAL_TASK_PROP_PREEMPTIVE_M = (kal_uintptr)(KAL_TASK_PROP_PREEMPTIVE); diff --git a/src/process.cppm b/src/process.cppm index 296ddc8..627d965 100644 --- a/src/process.cppm +++ b/src/process.cppm @@ -71,6 +71,7 @@ inline constexpr props bound_lifetime{KAL_PROCESS_PROP_BOUND_LIFETIME}; inline constexpr props job {KAL_PROCESS_PROP_JOB}; inline constexpr props stop_requested{KAL_PROCESS_PROP_STOP_REQUESTED}; inline constexpr props open_id {KAL_PROCESS_PROP_OPEN_ID}; +inline constexpr props one_string {KAL_PROCESS_PROP_ONE_STRING}; // 0.17.1 // The fields of kal_program_info, for `wanted' and `present' (0.17). namespace info { @@ -89,6 +90,7 @@ struct spawn_flag_tag; using spawn_flags = kal::props; inline constexpr spawn_flags bound_lifetime_flag{KAL_SPAWN_BOUND_LIFETIME}; +inline constexpr spawn_flags one_string_flag{KAL_SPAWN_ONE_STRING}; // 0.17.1 using how = kal_spawn; using job_handle = kal_job; From 16f2b739f21b2c785e031f72fcaa7610e6386067 Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Tue, 27 Oct 2026 09:25:54 +0900 Subject: [PATCH 2/2] conformance: the one-string position is one the specification assigns Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- conformance/src/sections/process.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conformance/src/sections/process.cpp b/conformance/src/sections/process.cpp index d858cc7..256aa29 100644 --- a/conformance/src/sections/process.cpp +++ b/conformance/src/sections/process.cpp @@ -297,7 +297,8 @@ void run() { | kal::process::bound_lifetime | kal::process::job | kal::process::stop_requested - | kal::process::open_id).bits; + | kal::process::open_id + | kal::process::one_string).bits; observe(kind::abi, sizeof(kal_preopen) == 3 * sizeof(kal_uintptr), "a directory grant occupies three machine words"); observe(kind::abi, sizeof(kal_spawn) == 6 * sizeof(kal_uintptr),