@scriptc/runtime 0.0.35 → 0.0.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/scr_async.c +1 -1
- package/src/scr_async_dyn.c +1 -1
- package/src/scr_console.c +2 -0
- package/src/scr_dc.c +1 -1
- package/src/scr_dyn_handle.c +1 -1
- package/src/scr_dyn_invoke.c +1 -1
- package/src/scr_fetch.c +1 -1
- package/src/scr_fetch_curl.c +1 -1
- package/src/scr_inspect_island.c +1 -1
- package/src/scr_lib.c +45 -1
- package/src/scr_library.c +36 -4
- package/src/scr_loop_epoll.c +1 -1
- package/src/scr_loop_wsapoll.c +1 -1
- package/src/scr_musl.c +1 -1
- package/src/scr_net.c +102 -18
- package/src/scr_net_island.c +1 -1
- package/src/scr_platform.h +1 -1
- package/src/scr_regex.c +1 -1
- package/src/scr_runtime.h +52 -21
- package/src/scr_string.c +11 -12
- package/src/scr_test.c +1 -1
- package/src/scr_tls_ca.c +1 -1
- package/src/scr_win.c +2 -2
- package/src/scr_zlib.c +2 -2
- package/src/scr_zlib_island.c +1 -1
- package/vendor/README.md +3 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scriptc/runtime",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "scriptc native runtime
|
|
3
|
+
"version": "0.0.36",
|
|
4
|
+
"description": "scriptc native runtime sources and vendored dependencies",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://scriptc.dev",
|
|
7
7
|
"repository": {
|
package/src/scr_async.c
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* same thread, own stack); the idle sleep is nanosleep (mingw-w64 ships
|
|
33
33
|
* it, over Sleep). poll(2) has no Windows arm — see the sleep seam in
|
|
34
34
|
* scr_loop_run: the poller-backed units (net/dgram/watch) are not built
|
|
35
|
-
* for win32 targets (
|
|
35
|
+
* for win32 targets (native-toolchain.ts gates them), so their fds never appear; the
|
|
36
36
|
* events unit DOES cross-compile (scr_events.c's win32 arm) and is
|
|
37
37
|
* served by a capped nanosleep — dispatch at the next turn's top, the
|
|
38
38
|
* cap bounding signal/stdin latency instead of a pollable wake fd. */
|
package/src/scr_async_dyn.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Checked-dynamic ASYNC surfaces (gated —
|
|
1
|
+
/* Checked-dynamic ASYNC surfaces (gated — native-toolchain.ts links this TU only when
|
|
2
2
|
* the IR carries the crossing libCalls or dyn dispatch: the scr_dc.c
|
|
3
3
|
* size-class precedent). Everything here rides scr_async.c's public
|
|
4
4
|
* machinery: the checked-dynamic tree-promise reaction helpers (.then/.catch/.finally
|
package/src/scr_console.c
CHANGED
|
@@ -71,6 +71,8 @@ static void scr_flush_at_exit(void) { fflush(stdout); }
|
|
|
71
71
|
|
|
72
72
|
static void scr_collect_cycles_at_exit(void) { scr_collect_cycles(); }
|
|
73
73
|
|
|
74
|
+
void scr_runtime_abi_v1(void) {}
|
|
75
|
+
|
|
74
76
|
void scr_init(void) {
|
|
75
77
|
#ifdef _WIN32
|
|
76
78
|
/* The CRT opens std streams in TEXT mode, which writes \n as \r\n. Node
|
package/src/scr_dc.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* node:diagnostics_channel — the in-process pub/sub core (scr_runtime.h
|
|
2
2
|
* has the API contract). Linked only when the IR carries dc.* libCalls
|
|
3
|
-
* (
|
|
3
|
+
* (native-toolchain.ts; the zlib gating precedent), pure data structure over the checked-dynamic tree —
|
|
4
4
|
* no loop hooks, no platform seams, cross-compiles everywhere.
|
|
5
5
|
*
|
|
6
6
|
* - The registry is process-global and append-only (Node's channels are
|
package/src/scr_dyn_handle.c
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* validators call them too), and the runtime-built listener adapter
|
|
7
7
|
* closures whose fire thunks box event tuples back into the checked-dynamic tree. Split
|
|
8
8
|
* out of scr_json.c so handle-free binaries keep their exact size
|
|
9
|
-
* class:
|
|
9
|
+
* class: native-toolchain.ts compiles this unit exactly when a user of it links (the
|
|
10
10
|
* net or emitter gate — http implies net).
|
|
11
11
|
*/
|
|
12
12
|
#include "scr_runtime.h"
|
package/src/scr_dyn_invoke.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* and its companions: JS String() over the checked-dynamic tree (scr_dyn_display — join
|
|
3
3
|
* and the error texts need it standalone) and Object.defineProperties
|
|
4
4
|
* over dyn values (scr_dyn_define_props). Linked only when the IR
|
|
5
|
-
* carries dynInvoke nodes or dyn.defineProps calls (
|
|
5
|
+
* carries dynInvoke nodes or dyn.defineProps calls (native-toolchain.ts gates on
|
|
6
6
|
* moduleUsesDynInvoke — the scr_assert.c precedent), so dispatch-free
|
|
7
7
|
* binaries keep their exact size class. The checked-dynamic tree itself lives in
|
|
8
8
|
* scr_json.c; this unit uses only its public surface plus ScrJsonBuf.
|
package/src/scr_fetch.c
CHANGED
|
@@ -7195,7 +7195,7 @@ void scr_fetch_install(void) {
|
|
|
7195
7195
|
* the loop alive nor dispatch. */
|
|
7196
7196
|
scr_net_install();
|
|
7197
7197
|
/* The island's node:http/https client bridge rides the same units and
|
|
7198
|
-
* is always compiled beside the native fetch (
|
|
7198
|
+
* is always compiled beside the native fetch (native-toolchain.ts) — embedded graphs
|
|
7199
7199
|
* that require node:http/https get working clients, not refusals. */
|
|
7200
7200
|
scr_net_island_install();
|
|
7201
7201
|
scr_island_set_fetch(fx_boot, NULL, NULL, fx_teardown);
|
package/src/scr_fetch_curl.c
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* REFERENCE implementation. The default fetch is scr_fetch.c (scriptc's
|
|
3
3
|
* own net stack: scr_net + scr_tls + scr_http's client parser + zlib);
|
|
4
4
|
* this file stays compilable for one release behind SCRIPTC_FETCH_CURL=1
|
|
5
|
-
* (
|
|
5
|
+
* (native-toolchain.ts selects exactly one of the two — same scr_fetch_install symbol,
|
|
6
6
|
* same island surface, same fixture contract) as the flip's reference,
|
|
7
7
|
* the C-backend-vs-LLVM precedent. Compiled and linked ONLY into
|
|
8
8
|
* --dynamic builds whose embedded npm graph references fetch (emit gates
|
package/src/scr_inspect_island.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* util.inspect over island `any` values — the one translation unit that
|
|
2
2
|
* references BOTH the inspect engine (scr_inspect.c) and the island
|
|
3
|
-
* (scr_island.c), so
|
|
3
|
+
* (scr_island.c), so native-toolchain.ts links it exactly when a --dynamic build's IR
|
|
4
4
|
* carries insp.* libCalls (each half alone stays independent: static
|
|
5
5
|
* inspect builds never pull engine symbols, inspect-free dynamic builds
|
|
6
6
|
* never pull the renderer).
|
package/src/scr_lib.c
CHANGED
|
@@ -114,17 +114,39 @@ static SCR_TL ScrStr *scr_arch_str = NULL; /* interned process.arch */
|
|
|
114
114
|
static SCR_TL ScrStr *scr_versions_node_str = NULL; /* interned process.versions.node */
|
|
115
115
|
static SCR_TL ScrStr *scr_versions_openssl_str = NULL; /* interned process.versions.openssl */
|
|
116
116
|
|
|
117
|
+
/* Keep lazy process values out of the startup cleanup root. The executable
|
|
118
|
+
* linker can discard an otherwise-unused getter, but an unconditional atexit
|
|
119
|
+
* callback that mentions every cache would still retain each cache cell (and
|
|
120
|
+
* its symbol) in a tiny hello-world. Each getter below instead registers its
|
|
121
|
+
* own cleanup only when the value is first materialized. That is equivalent
|
|
122
|
+
* at process exit and retains the RC-audit cleanup guarantee for the values a
|
|
123
|
+
* program actually observes. */
|
|
117
124
|
static void scr_lib_cleanup(void) {
|
|
118
125
|
scr_arr_release(scr_argv_arr);
|
|
119
126
|
scr_argv_arr = NULL;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static void scr_process_platform_cleanup(void) {
|
|
120
130
|
scr_str_release(scr_platform_str);
|
|
121
131
|
scr_platform_str = NULL;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
static void scr_process_exec_path_cleanup(void) {
|
|
122
135
|
scr_str_release(scr_exec_path_str);
|
|
123
136
|
scr_exec_path_str = NULL;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
static void scr_process_arch_cleanup(void) {
|
|
124
140
|
scr_str_release(scr_arch_str);
|
|
125
141
|
scr_arch_str = NULL;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
static void scr_process_versions_node_cleanup(void) {
|
|
126
145
|
scr_str_release(scr_versions_node_str);
|
|
127
146
|
scr_versions_node_str = NULL;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static void scr_process_versions_openssl_cleanup(void) {
|
|
128
150
|
scr_str_release(scr_versions_openssl_str);
|
|
129
151
|
scr_versions_openssl_str = NULL;
|
|
130
152
|
}
|
|
@@ -165,7 +187,14 @@ void scr_lib_init(int argc, char **argv) {
|
|
|
165
187
|
* atexit handlers); the interned process values above still intern lazily
|
|
166
188
|
* on first read, so the library reset seam releases them here instead —
|
|
167
189
|
* scr_library_reset (scr_library.c) calls this every session reset. */
|
|
168
|
-
void scr_lib_session_cleanup(void) {
|
|
190
|
+
void scr_lib_session_cleanup(void) {
|
|
191
|
+
scr_lib_cleanup();
|
|
192
|
+
scr_process_platform_cleanup();
|
|
193
|
+
scr_process_exec_path_cleanup();
|
|
194
|
+
scr_process_arch_cleanup();
|
|
195
|
+
scr_process_versions_node_cleanup();
|
|
196
|
+
scr_process_versions_openssl_cleanup();
|
|
197
|
+
}
|
|
169
198
|
#endif
|
|
170
199
|
|
|
171
200
|
/* Raw argv accessors for the island's process shim (scr_island.c): the
|
|
@@ -204,6 +233,9 @@ ScrStr *scr_process_platform(void) {
|
|
|
204
233
|
scr_platform_str = scr_str_new("win32", 5);
|
|
205
234
|
#else
|
|
206
235
|
scr_platform_str = scr_str_new("unknown", 7);
|
|
236
|
+
#endif
|
|
237
|
+
#ifndef SCR_LIB
|
|
238
|
+
atexit(scr_process_platform_cleanup);
|
|
207
239
|
#endif
|
|
208
240
|
}
|
|
209
241
|
return scr_str_retain(scr_platform_str);
|
|
@@ -223,6 +255,9 @@ ScrStr *scr_process_arch(void) {
|
|
|
223
255
|
scr_arch_str = scr_str_new("x64", 3);
|
|
224
256
|
#else
|
|
225
257
|
scr_arch_str = scr_str_new("unknown", 7);
|
|
258
|
+
#endif
|
|
259
|
+
#ifndef SCR_LIB
|
|
260
|
+
atexit(scr_process_arch_cleanup);
|
|
226
261
|
#endif
|
|
227
262
|
}
|
|
228
263
|
return scr_str_retain(scr_arch_str);
|
|
@@ -237,6 +272,9 @@ ScrStr *scr_process_versions_node(void) {
|
|
|
237
272
|
if (!scr_versions_node_str) {
|
|
238
273
|
scr_versions_node_str =
|
|
239
274
|
scr_str_new(SCR_NODE_COMPAT_VERSION, sizeof(SCR_NODE_COMPAT_VERSION) - 1);
|
|
275
|
+
#ifndef SCR_LIB
|
|
276
|
+
atexit(scr_process_versions_node_cleanup);
|
|
277
|
+
#endif
|
|
240
278
|
}
|
|
241
279
|
return scr_str_retain(scr_versions_node_str);
|
|
242
280
|
}
|
|
@@ -253,6 +291,9 @@ ScrStr *scr_process_versions_openssl(void) {
|
|
|
253
291
|
if (!scr_versions_openssl_str) {
|
|
254
292
|
scr_versions_openssl_str =
|
|
255
293
|
scr_str_new(SCR_OPENSSL_COMPAT_VERSION, sizeof(SCR_OPENSSL_COMPAT_VERSION) - 1);
|
|
294
|
+
#ifndef SCR_LIB
|
|
295
|
+
atexit(scr_process_versions_openssl_cleanup);
|
|
296
|
+
#endif
|
|
256
297
|
}
|
|
257
298
|
return scr_str_retain(scr_versions_openssl_str);
|
|
258
299
|
}
|
|
@@ -289,6 +330,9 @@ ScrStr *scr_process_exec_path(void) {
|
|
|
289
330
|
const char *use = realpath(raw, resolved) != NULL ? resolved : raw;
|
|
290
331
|
#endif
|
|
291
332
|
scr_exec_path_str = scr_str_new(use, strlen(use));
|
|
333
|
+
#ifndef SCR_LIB
|
|
334
|
+
atexit(scr_process_exec_path_cleanup);
|
|
335
|
+
#endif
|
|
292
336
|
}
|
|
293
337
|
return scr_str_retain(scr_exec_path_str);
|
|
294
338
|
}
|
package/src/scr_library.c
CHANGED
|
@@ -64,6 +64,10 @@ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
|
64
64
|
|
|
65
65
|
static SCR_TL ScrLibCbFn scr_library_cb_fns[SCR_LIB_MAX_CALLBACKS];
|
|
66
66
|
static SCR_TL void *scr_library_cb_ctxs[SCR_LIB_MAX_CALLBACKS];
|
|
67
|
+
/* A typed host callback runs synchronously inside one ABI entry. Like the
|
|
68
|
+
* sink, slots, poison, arena, and current-entry symbol, this belongs to the
|
|
69
|
+
* localized / thread-instanced library copy rather than the process. */
|
|
70
|
+
static SCR_TL size_t scr_library_callback_depth = 0;
|
|
67
71
|
|
|
68
72
|
void scr_library_cb_set(size_t slot, ScrLibCbFn fn, void *ctx) {
|
|
69
73
|
/* A pure store, the sink registration's rule: latest wins, NULL clears,
|
|
@@ -82,6 +86,15 @@ ScrLibCbFn scr_library_cb_require(size_t slot, const char *trap_msg) {
|
|
|
82
86
|
|
|
83
87
|
void *scr_library_cb_ctx(size_t slot) { return scr_library_cb_ctxs[slot]; }
|
|
84
88
|
|
|
89
|
+
void scr_library_callback_begin(void) { scr_library_callback_depth++; }
|
|
90
|
+
|
|
91
|
+
void scr_library_callback_end(void) {
|
|
92
|
+
/* Generated calls pair this only with a normally returned host callback.
|
|
93
|
+
* A callback that illegally unwinds leaves the depth set, so a later ABI
|
|
94
|
+
* entry fails deterministically instead of silently reusing the instance. */
|
|
95
|
+
if (scr_library_callback_depth != 0) scr_library_callback_depth--;
|
|
96
|
+
}
|
|
97
|
+
|
|
85
98
|
/* ── the trap funnel, library expansion ───────────────────────────────────
|
|
86
99
|
* Poison first (the sink may longjmp to a host frame below the entry — the
|
|
87
100
|
* conforming survival pattern), then deliver exactly once, then abort:
|
|
@@ -111,8 +124,9 @@ void *scr_library_cb_ctx(size_t slot) { return scr_library_cb_ctxs[slot]; }
|
|
|
111
124
|
* external symbol before dispatching into core code. A single static slot
|
|
112
125
|
* is sound — exactly one core is live per copy of this state (the sole
|
|
113
126
|
* core in a classic process; each archive's own instance under
|
|
114
|
-
* abi.localize_runtime, where this slot is a per-instance local),
|
|
115
|
-
*
|
|
127
|
+
* abi.localize_runtime, where this slot is a per-instance local), re-entry
|
|
128
|
+
* from a host callback is rejected before core work begins, and a trap can
|
|
129
|
+
* only fire while an entry is on the stack.
|
|
116
130
|
* NULL (never entered) renders as the empty symbol field. */
|
|
117
131
|
static SCR_TL const char *scr_library_entry_symbol = NULL;
|
|
118
132
|
|
|
@@ -134,6 +148,7 @@ static const struct {
|
|
|
134
148
|
{"scriptc: out of memory", "SC4017"}, /* allocation failure */
|
|
135
149
|
{"scriptc: internal error: ", "SC4018"}, /* internal invariant failure */
|
|
136
150
|
{"scriptc: library callback ", "SC4025"}, /* unregistered host callback */
|
|
151
|
+
{"scriptc: library entry ", "SC4026"}, /* host callback re-entry */
|
|
137
152
|
};
|
|
138
153
|
|
|
139
154
|
static const char *scr_library_trap_code(const char *msg, size_t len) {
|
|
@@ -229,11 +244,28 @@ __attribute__((noinline)) _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
|
229
244
|
|
|
230
245
|
/* ── entry prologues ──────────────────────────────────────────────────── */
|
|
231
246
|
|
|
247
|
+
static _Noreturn void scr_library_callback_reentry(const char *entry_symbol) {
|
|
248
|
+
/* Attribute the detected trap to the attempted INNER ABI symbol. Clear
|
|
249
|
+
* depth before delivery: a conforming sink may longjmp to a host recovery
|
|
250
|
+
* frame, and its poisoned instance must not retain stale callback-active
|
|
251
|
+
* state that would change the established pure-registration behavior. */
|
|
252
|
+
scr_library_entry_symbol = entry_symbol;
|
|
253
|
+
scr_library_callback_depth = 0;
|
|
254
|
+
scr_trap_fmt("scriptc: library entry '%s' invoked from a host callback\n", entry_symbol);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
void scr_library_callback_entry_guard(const char *entry_symbol) {
|
|
258
|
+
if (scr_library_callback_depth != 0) scr_library_callback_reentry(entry_symbol);
|
|
259
|
+
}
|
|
260
|
+
|
|
232
261
|
void scr_library_entry(bool reset_arena, const char *entry_symbol) {
|
|
233
262
|
/* Record the entry symbol FIRST so even a poisoned-abort's core dump
|
|
234
|
-
|
|
235
|
-
|
|
263
|
+
* names the entry; a trap anywhere below (the arena reset's OOM
|
|
264
|
+
* included) then reports the right symbol. */
|
|
236
265
|
scr_library_entry_symbol = entry_symbol;
|
|
266
|
+
/* Re-entry must win over poison and reset: no inner ABI entry may mutate
|
|
267
|
+
* globals, release arena data, collect, or replace state from a callback. */
|
|
268
|
+
if (scr_library_callback_depth != 0) scr_library_callback_reentry(entry_symbol);
|
|
237
269
|
/* A poisoned library's entries abort deterministically — never through the
|
|
238
270
|
* sink again (it received its exactly-once message when the trap fired),
|
|
239
271
|
* never into a heap whose invariants already failed. */
|
package/src/scr_loop_epoll.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* The Linux backend of the platform readiness contract (scr_platform.h):
|
|
2
2
|
* epoll for fd readiness, one timerfd per armed one-shot timer. This is
|
|
3
|
-
* the LIVE Linux poller behind scr_net.c and scr_dgram.c (
|
|
3
|
+
* the LIVE Linux poller behind scr_net.c and scr_dgram.c (native-toolchain.ts links it
|
|
4
4
|
* alongside scr_loop_kqueue.c whenever those units compile; each TU is
|
|
5
5
|
* empty off its platform). Child-exit wakeups are NOT here: scr_child.c
|
|
6
6
|
* keeps its narrow seam inline (kqueue EVFILT_PROC on BSD, pidfd_open +
|
package/src/scr_loop_wsapoll.c
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* The Windows backend of the platform readiness contract (scr_platform.h):
|
|
2
2
|
* WSAPoll for socket readiness, deadline bookkeeping for the one-shot
|
|
3
3
|
* timers (no timerfd analogue — scrp_drain expires due keys against the
|
|
4
|
-
* loop's scr_now_ms clock).
|
|
4
|
+
* loop's scr_now_ms clock). native-toolchain.ts links this TU alongside the kqueue and
|
|
5
5
|
* epoll backends whenever a poller-using unit compiles; each is empty off
|
|
6
6
|
* its platform.
|
|
7
7
|
*
|
package/src/scr_musl.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* musl libc shim — compiled into linux-musl target builds only (
|
|
1
|
+
/* musl libc shim — compiled into linux-musl target builds only (native-toolchain.ts adds
|
|
2
2
|
* this TU together with -DSCR_MUSL). musl deliberately provides no libc
|
|
3
3
|
* identification macro, so the target-selected project macro is the guard.
|
|
4
4
|
*
|
package/src/scr_net.c
CHANGED
|
@@ -107,6 +107,20 @@
|
|
|
107
107
|
#include <netinet/in.h>
|
|
108
108
|
#include <netinet/tcp.h>
|
|
109
109
|
#include <sys/socket.h>
|
|
110
|
+
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(_AIX) || defined(__sun)
|
|
111
|
+
#include <sys/param.h>
|
|
112
|
+
#endif
|
|
113
|
+
#endif
|
|
114
|
+
|
|
115
|
+
/* MinGW's errno headers do not expose ENOTSUP on every supported toolchain.
|
|
116
|
+
* Keep a stable internal value for the Node/libuv unsupported reuse-port
|
|
117
|
+
* result, while preserving the platform's EOPNOTSUPP spelling when present. */
|
|
118
|
+
#ifndef ENOTSUP
|
|
119
|
+
#ifdef EOPNOTSUPP
|
|
120
|
+
#define ENOTSUP EOPNOTSUPP
|
|
121
|
+
#else
|
|
122
|
+
#define ENOTSUP 4095
|
|
123
|
+
#endif
|
|
110
124
|
#endif
|
|
111
125
|
|
|
112
126
|
static void scr_net_oom(void) {
|
|
@@ -275,6 +289,10 @@ static const char *scr_net_errname(int err) {
|
|
|
275
289
|
case EHOSTDOWN: return "EHOSTDOWN"; /* absent from the win32 CRT */
|
|
276
290
|
#endif
|
|
277
291
|
case EINVAL: return "EINVAL";
|
|
292
|
+
case ENOTSUP: return "ENOTSUP";
|
|
293
|
+
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
|
|
294
|
+
case EOPNOTSUPP: return "EOPNOTSUPP";
|
|
295
|
+
#endif
|
|
278
296
|
default: return "EUNKNOWN";
|
|
279
297
|
}
|
|
280
298
|
}
|
|
@@ -710,6 +728,63 @@ static void scr_net_listen_reuseaddr(int fd) {
|
|
|
710
728
|
#endif
|
|
711
729
|
}
|
|
712
730
|
|
|
731
|
+
/* Node/libuv's TCP reuse-port matrix. SO_REUSEPORT is deliberately NOT
|
|
732
|
+
* selected merely because a platform header happens to expose it: macOS's
|
|
733
|
+
* meaning is not the required TCP load-balancing contract, and Windows'
|
|
734
|
+
* SO_REUSEADDR is port hijacking rather than reuse-port support. FreeBSD's
|
|
735
|
+
* ordinary SO_REUSEPORT does not distribute connections, so FreeBSD 12+
|
|
736
|
+
* uses the load-balancing spelling instead. A setsockopt failure is returned
|
|
737
|
+
* to the caller so an unsupported kernel cannot silently become a singleton. */
|
|
738
|
+
static int scr_net_listen_reuseport(int fd) {
|
|
739
|
+
int rc;
|
|
740
|
+
#if defined(__FreeBSD__) && defined(__FreeBSD_version) && \
|
|
741
|
+
__FreeBSD_version >= 1200000 && defined(SO_REUSEPORT_LB)
|
|
742
|
+
int one = 1;
|
|
743
|
+
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT_LB, &one, sizeof one);
|
|
744
|
+
#elif (defined(__linux__) || defined(_AIX73) || \
|
|
745
|
+
(defined(__DragonFly__) && defined(__DragonFly_version) && __DragonFly_version >= 300600) || \
|
|
746
|
+
(defined(__sun) && !defined(__illumos__) && defined(SO_FLOW_NAME))) && \
|
|
747
|
+
defined(SO_REUSEPORT)
|
|
748
|
+
int one = 1;
|
|
749
|
+
rc = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof one);
|
|
750
|
+
#else
|
|
751
|
+
(void)fd;
|
|
752
|
+
errno = ENOTSUP;
|
|
753
|
+
return -1;
|
|
754
|
+
#endif
|
|
755
|
+
#if defined(__linux__) && defined(ENOPROTOOPT)
|
|
756
|
+
/* Linux kernels predating 3.9 expose no reuse-port TCP support. Keep
|
|
757
|
+
* Node's stable unsupported result instead of leaking ENOPROTOOPT. */
|
|
758
|
+
if (rc != 0 && errno == ENOPROTOOPT) errno = ENOTSUP;
|
|
759
|
+
#endif
|
|
760
|
+
return rc;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/* Shared bind setup for both host-less and explicit-interface listeners.
|
|
764
|
+
* SO_REUSEADDR remains first, reuse-port is requested next, and both are
|
|
765
|
+
* complete before bind/listen. The returned errno is the native failure. */
|
|
766
|
+
static int scr_net_bind_listen(int fd, const struct sockaddr *sa, socklen_t salen,
|
|
767
|
+
bool reuse_port) {
|
|
768
|
+
scr_net_listen_reuseaddr(fd);
|
|
769
|
+
if (reuse_port && scr_net_listen_reuseport(fd) != 0) return -1;
|
|
770
|
+
scr_net_nonblock(fd);
|
|
771
|
+
int rc = bind(fd, sa, salen);
|
|
772
|
+
if (rc == 0) rc = listen(fd, 511); /* Node's default backlog */
|
|
773
|
+
return rc;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
static const char *scr_net_listen_reason(int err, bool explicit_host) {
|
|
777
|
+
if (err == EADDRINUSE) return "address already in use";
|
|
778
|
+
#ifdef EADDRNOTAVAIL
|
|
779
|
+
if (explicit_host && err == EADDRNOTAVAIL) return "address not available";
|
|
780
|
+
#endif
|
|
781
|
+
if (err == ENOTSUP) return "operation not supported";
|
|
782
|
+
#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
|
|
783
|
+
if (err == EOPNOTSUPP) return "operation not supported";
|
|
784
|
+
#endif
|
|
785
|
+
return "permission denied";
|
|
786
|
+
}
|
|
787
|
+
|
|
713
788
|
/* write(2) to a socket with SIGPIPE suppressed. macOS sets SO_NOSIGPIPE
|
|
714
789
|
* per fd above (send() path unchanged: write, exactly the historical
|
|
715
790
|
* call); Linux has no SO_NOSIGPIPE — MSG_NOSIGNAL on each send is the
|
|
@@ -1280,7 +1355,8 @@ ScrNetServer *scr_net_create_server(ScrClosure *handler /*moves, nullable*/, Scr
|
|
|
1280
1355
|
* 'error'); success defers the listen callback ('listening') to the next
|
|
1281
1356
|
* dispatch pass, Node's next-tick emit. Binds like Node's host-less
|
|
1282
1357
|
* listen: IPv6 any with dual-stack when the kernel allows, IPv4 fallback. */
|
|
1283
|
-
void
|
|
1358
|
+
static void scr_net_listen_any(ScrNetServer *s, double port, bool reuse_port,
|
|
1359
|
+
ScrClosure *cb /*moves, nullable*/) {
|
|
1284
1360
|
if (cb) scr_net_ls_add(&s->listening_cbs, cb, NULL, true);
|
|
1285
1361
|
if (s->listening || s->close_emitted) return;
|
|
1286
1362
|
if (!scr_net_poller_init()) {
|
|
@@ -1300,8 +1376,6 @@ void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullab
|
|
|
1300
1376
|
fputs("scriptc: socket() failed\n", stderr);
|
|
1301
1377
|
abort();
|
|
1302
1378
|
}
|
|
1303
|
-
scr_net_listen_reuseaddr(fd);
|
|
1304
|
-
scr_net_nonblock(fd);
|
|
1305
1379
|
int rc;
|
|
1306
1380
|
if (v6) {
|
|
1307
1381
|
struct sockaddr_in6 addr;
|
|
@@ -1309,23 +1383,22 @@ void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullab
|
|
|
1309
1383
|
addr.sin6_family = AF_INET6;
|
|
1310
1384
|
addr.sin6_addr = in6addr_any;
|
|
1311
1385
|
addr.sin6_port = htons((uint16_t)p);
|
|
1312
|
-
rc =
|
|
1386
|
+
rc = scr_net_bind_listen(fd, (struct sockaddr *)&addr, sizeof addr, reuse_port);
|
|
1313
1387
|
} else {
|
|
1314
1388
|
struct sockaddr_in addr;
|
|
1315
1389
|
memset(&addr, 0, sizeof addr);
|
|
1316
1390
|
addr.sin_family = AF_INET;
|
|
1317
1391
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
1318
1392
|
addr.sin_port = htons((uint16_t)p);
|
|
1319
|
-
rc =
|
|
1393
|
+
rc = scr_net_bind_listen(fd, (struct sockaddr *)&addr, sizeof addr, reuse_port);
|
|
1320
1394
|
}
|
|
1321
|
-
if (rc == 0) rc = listen(fd, 511); /* Node's default backlog */
|
|
1322
1395
|
if (rc != 0) {
|
|
1323
1396
|
int err = errno;
|
|
1324
1397
|
close(fd);
|
|
1325
1398
|
char msg[128];
|
|
1326
1399
|
/* Node: "listen EADDRINUSE: address already in use :::4000" */
|
|
1327
1400
|
snprintf(msg, sizeof msg, "listen %s: %s %s:%d", scr_net_errname(err),
|
|
1328
|
-
err
|
|
1401
|
+
scr_net_listen_reason(err, false),
|
|
1329
1402
|
v6 ? "::" : "0.0.0.0", p);
|
|
1330
1403
|
if (!s->pending_err) s->pending_err = scr_str_new(msg, strlen(msg));
|
|
1331
1404
|
scr_net_server_register(s); /* the sweep delivers the failure */
|
|
@@ -1347,7 +1420,11 @@ void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullab
|
|
|
1347
1420
|
scr_net_server_register(s);
|
|
1348
1421
|
}
|
|
1349
1422
|
|
|
1350
|
-
|
|
1423
|
+
void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullable*/) {
|
|
1424
|
+
scr_net_listen_any(s, port, false, cb);
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/* listen({ port, host, ipv6Only, reusePort }) — the explicit-interface bind
|
|
1351
1428
|
* (portless's listenOnProxyInterface): host is an IP literal ("" = the
|
|
1352
1429
|
* host-less dual-stack default above; "localhost" pins to 127.0.0.1, the
|
|
1353
1430
|
* connect-side divergence); ipv6Only sets IPV6_V6ONLY before the bind
|
|
@@ -1355,10 +1432,11 @@ void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullab
|
|
|
1355
1432
|
* listener, exactly the portless pair). Failures are the async 'error'
|
|
1356
1433
|
* with Node's listen message naming the requested host; a non-IP host is
|
|
1357
1434
|
* the async getaddrinfo ENOTFOUND (no resolver in this slice). */
|
|
1358
|
-
void
|
|
1359
|
-
|
|
1435
|
+
static void scr_net_listen_opts_impl(ScrNetServer *s, double port, ScrStr *host /*borrowed*/,
|
|
1436
|
+
bool ipv6_only, bool reuse_port,
|
|
1437
|
+
ScrClosure *cb /*moves, nullable*/) {
|
|
1360
1438
|
if (host == NULL || host->len == 0) {
|
|
1361
|
-
|
|
1439
|
+
scr_net_listen_any(s, port, reuse_port, cb);
|
|
1362
1440
|
return;
|
|
1363
1441
|
}
|
|
1364
1442
|
if (cb) scr_net_ls_add(&s->listening_cbs, cb, NULL, true);
|
|
@@ -1406,18 +1484,13 @@ void scr_net_listen_opts(ScrNetServer *s, double port, ScrStr *host /*borrowed*/
|
|
|
1406
1484
|
int only = ipv6_only ? 1 : 0;
|
|
1407
1485
|
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &only, sizeof only);
|
|
1408
1486
|
}
|
|
1409
|
-
|
|
1410
|
-
scr_net_nonblock(fd);
|
|
1411
|
-
int rc = bind(fd, sa, salen);
|
|
1412
|
-
if (rc == 0) rc = listen(fd, 511); /* Node's default backlog */
|
|
1487
|
+
int rc = scr_net_bind_listen(fd, sa, salen, reuse_port);
|
|
1413
1488
|
if (rc != 0) {
|
|
1414
1489
|
int err = errno;
|
|
1415
1490
|
close(fd);
|
|
1416
1491
|
char msg[160];
|
|
1417
1492
|
snprintf(msg, sizeof msg, "listen %s: %s %s:%d", scr_net_errname(err),
|
|
1418
|
-
err
|
|
1419
|
-
: err == EADDRNOTAVAIL ? "address not available"
|
|
1420
|
-
: "permission denied",
|
|
1493
|
+
scr_net_listen_reason(err, true),
|
|
1421
1494
|
h, p);
|
|
1422
1495
|
if (!s->pending_err) s->pending_err = scr_str_new(msg, strlen(msg));
|
|
1423
1496
|
scr_net_server_register(s);
|
|
@@ -1440,6 +1513,17 @@ void scr_net_listen_opts(ScrNetServer *s, double port, ScrStr *host /*borrowed*/
|
|
|
1440
1513
|
scr_net_server_register(s);
|
|
1441
1514
|
}
|
|
1442
1515
|
|
|
1516
|
+
void scr_net_listen_opts(ScrNetServer *s, double port, ScrStr *host /*borrowed*/,
|
|
1517
|
+
bool ipv6_only, ScrClosure *cb /*moves, nullable*/) {
|
|
1518
|
+
scr_net_listen_opts_impl(s, port, host, ipv6_only, false, cb);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
void scr_net_listen_opts_reuse_port(ScrNetServer *s, double port, ScrStr *host /*borrowed*/,
|
|
1522
|
+
bool ipv6_only, bool reuse_port,
|
|
1523
|
+
ScrClosure *cb /*moves, nullable*/) {
|
|
1524
|
+
scr_net_listen_opts_impl(s, port, host, ipv6_only, reuse_port, cb);
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1443
1527
|
double scr_net_server_port(ScrNetServer *s) { return (double)s->port; }
|
|
1444
1528
|
|
|
1445
1529
|
double scr_net_server_timeout_get(ScrNetServer *s, double field) {
|
package/src/scr_net_island.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* The island's node:http/node:https CLIENT ↔ the socket units — the one
|
|
2
2
|
* translation unit referencing BOTH scr_http/scr_tls and the engine (the
|
|
3
|
-
* scr_zlib_island.c precedent):
|
|
3
|
+
* scr_zlib_island.c precedent): native-toolchain.ts compiles it exactly when a
|
|
4
4
|
* --dynamic build links the socket units, and the emitted main calls
|
|
5
5
|
* scr_net_island_install before any island entry. Builds without it keep
|
|
6
6
|
* the island's "does not provide the 'node:http' builtin" refusal.
|
package/src/scr_platform.h
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* child-exit filter, and the zero-timeout drains. This header names that
|
|
13
13
|
* plumbing so each unit can call one spelling and link either backend.
|
|
14
14
|
*
|
|
15
|
-
* STATUS: LIVE. scr_net.c and scr_dgram.c call this contract;
|
|
15
|
+
* STATUS: LIVE. scr_net.c and scr_dgram.c call this contract; native-toolchain.ts
|
|
16
16
|
* links BOTH backends whenever either unit compiles (scr_loop_kqueue.c —
|
|
17
17
|
* a stateless spelling of the units' historical inline syscall
|
|
18
18
|
* sequences, byte-identical on macOS by construction — and
|
package/src/scr_regex.c
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* implementation the dynamic island uses — compiled standalone (libregexp.c
|
|
5
5
|
* + libunicode.c; cutils is header-only) and linked ONLY into programs that
|
|
6
6
|
* contain a regex literal. This file is likewise regex-only: it is NOT in
|
|
7
|
-
* the always-compiled runtime source list (see
|
|
7
|
+
* the always-compiled runtime source list (see native-toolchain.ts), so regex-free
|
|
8
8
|
* programs keep a byte-identical link line.
|
|
9
9
|
*
|
|
10
10
|
* - Every ScrRegex today is an immortal interned literal (the compiler
|
package/src/scr_runtime.h
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
/* ── libc shims ─────────────────────────────────────────────────────────
|
|
19
19
|
* Win32's missing POSIX/BSD functions live in scr_win.c. Zig's musl sysroot
|
|
20
20
|
* additionally lacks arc4random_buf; scr_musl.c supplies it from Linux's
|
|
21
|
-
* getrandom syscall. Both files are selected by
|
|
21
|
+
* getrandom syscall. Both files are selected by native-toolchain.ts only for their target. */
|
|
22
22
|
#ifdef _WIN32
|
|
23
23
|
#include <time.h> /* time_t / struct tm for the gmtime_r shim */
|
|
24
24
|
char *stpcpy(char *dst, const char *src);
|
|
@@ -53,6 +53,10 @@ void arc4random_buf(void *buf, size_t n);
|
|
|
53
53
|
* flush-at-exit, RC audit registration (when built with -DSCR_RC_AUDIT).
|
|
54
54
|
* JavaScript-visible writes flush before returning. */
|
|
55
55
|
void scr_init(void);
|
|
56
|
+
/* Program objects emitted by the bundled LLVM helper reference this symbol.
|
|
57
|
+
* Its versioned spelling makes a mismatched manual runtime link fail before
|
|
58
|
+
* the program can start. */
|
|
59
|
+
void scr_runtime_abi_v1(void);
|
|
56
60
|
|
|
57
61
|
/* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ──────
|
|
58
62
|
* Every unrecoverable runtime trap — OOM, semantic range traps, internal-
|
|
@@ -104,7 +108,8 @@ typedef struct ScrBytes ScrBytes;
|
|
|
104
108
|
* Every trap the runtime DETECTS arrives structured: the funnel assembles
|
|
105
109
|
* the baseline human line into field 0 unchanged, a stable code for the
|
|
106
110
|
* trap kind (the compiler registry's runtime family — SC4013–SC4019 plus
|
|
107
|
-
* the SC4025 unregistered-callback
|
|
111
|
+
* the SC4025 unregistered-callback and SC4026 callback-re-entry traps,
|
|
112
|
+
* classified in scr_library.c), the
|
|
108
113
|
* entry symbol recorded by the trapping
|
|
109
114
|
* entry's prologue, and the profile's remediation for that code when the
|
|
110
115
|
* program TU's overlay table declares one (the whole fourth field is
|
|
@@ -129,16 +134,23 @@ void scr_library_set_sink(ScrLibSinkFn fn, void *ctx); /* latest wins */
|
|
|
129
134
|
*
|
|
130
135
|
* Registration is a pure store like the sink's (no entry prologue, no
|
|
131
136
|
* poison guard, legal before init); latest wins, NULL clears, and
|
|
132
|
-
* registrations persist across init/reset.
|
|
137
|
+
* registrations persist across init/reset. While a host callback is active,
|
|
138
|
+
* its registration entry is rejected before name dispatch or a store, just
|
|
139
|
+
* like every runtime-touching ABI entry. Slots are per-copy of this
|
|
133
140
|
* state, exactly the sink's story: per-archive under abi.localize_runtime,
|
|
134
141
|
* per-thread instance under abi.instance_per_thread (SCR_TL) — a callback
|
|
135
142
|
* registered on thread T fires only for T's instance. The host's callback
|
|
136
143
|
* runs on the calling thread inside the entry's dynamic extent and must
|
|
137
|
-
* NOT call back into any library entry (
|
|
138
|
-
* unwind/longjmp across library
|
|
139
|
-
* what outlives the call, return.
|
|
140
|
-
*
|
|
141
|
-
|
|
144
|
+
* NOT call back into any library entry (exports, init, reset, collect, sink
|
|
145
|
+
* registration, or callback registration) or unwind/longjmp across library
|
|
146
|
+
* frames: read the borrowed buffers, copy what outlives the call, return.
|
|
147
|
+
* A re-entry is a detected SC4026 trap: it poisons only this library
|
|
148
|
+
* instance, delivers exactly once to the already-registered sink, names the
|
|
149
|
+
* attempted inner ABI symbol in structured field 2, then aborts if the sink
|
|
150
|
+
* returns. A later host-loop turn may enter normally after the callback has
|
|
151
|
+
* returned. Buffer parameters are borrowed for the duration of the call
|
|
152
|
+
* only. */
|
|
153
|
+
#define SCR_LIB_MAX_CALLBACKS 32 /* keep in step with LIB_MAX_CALLBACKS (library/library-profile.ts) */
|
|
142
154
|
/* The stored shape: generated call sites cast a slot's pointer to the
|
|
143
155
|
* channel's typed shape before calling. */
|
|
144
156
|
typedef void (*ScrLibCbFn)(void);
|
|
@@ -147,6 +159,15 @@ void scr_library_cb_set(size_t slot, ScrLibCbFn fn, void *ctx);
|
|
|
147
159
|
* trap_msg (never returns NULL). */
|
|
148
160
|
ScrLibCbFn scr_library_cb_require(size_t slot, const char *trap_msg);
|
|
149
161
|
void *scr_library_cb_ctx(size_t slot);
|
|
162
|
+
/* Generated typed call sites bracket only the actual host-function call.
|
|
163
|
+
* End is reached only after a normal return; an illegal unwind deliberately
|
|
164
|
+
* leaves the depth active so the next ABI entry is rejected. */
|
|
165
|
+
void scr_library_callback_begin(void);
|
|
166
|
+
void scr_library_callback_end(void);
|
|
167
|
+
/* Registration wrappers bypass scr_library_entry because their normal path
|
|
168
|
+
* is a pure store. They call this first so callback-time registration is
|
|
169
|
+
* rejected before dispatch, NULL handling, or mutation. */
|
|
170
|
+
void scr_library_callback_entry_guard(const char *entry_symbol);
|
|
150
171
|
|
|
151
172
|
/* Entry prologue: aborts deterministically when the library is poisoned (a
|
|
152
173
|
* trap already fired — no profile entry may run again; recovery is process
|
|
@@ -155,10 +176,11 @@ void *scr_library_cb_ctx(size_t slot);
|
|
|
155
176
|
* entry_symbol is the generated entry's external symbol exactly as the
|
|
156
177
|
* host linked it (a static string in the program TU): the prologue records
|
|
157
178
|
* it in the funnel's current-entry slot so a detected trap's structured
|
|
158
|
-
* message can name the trapping entry
|
|
159
|
-
*
|
|
160
|
-
* the mode entries (reset, collect) record theirs too
|
|
161
|
-
*
|
|
179
|
+
* message can name the trapping entry. A host callback's attempted nested
|
|
180
|
+
* entry is rejected first and replaces this slot with that inner symbol.
|
|
181
|
+
* Init and the mode entries (reset, collect) record theirs too. The two
|
|
182
|
+
* profile identity getters are the explicit pure-data exception: they touch
|
|
183
|
+
* no mutable runtime state and remain callable before init and after poison. */
|
|
162
184
|
void scr_library_entry(bool reset_arena, const char *entry_symbol);
|
|
163
185
|
void scr_library_arena_reset(void);
|
|
164
186
|
/* The mode-provided collect entry's body: arena reset + a full cycle
|
|
@@ -196,7 +218,8 @@ _Noreturn void scr_trap_len(const char *msg, size_t len);
|
|
|
196
218
|
* (both emissions emit identical data) and consumed by the funnel when it
|
|
197
219
|
* assembles a detected trap's structured message: flat triples of
|
|
198
220
|
* (code, teaching-or-NULL, remediation-or-NULL), one per runtime trap code
|
|
199
|
-
* (the SC4013–SC4019 family plus SC4025) the profile declares
|
|
221
|
+
* (the SC4013–SC4019 family plus SC4025 and SC4026) the profile declares
|
|
222
|
+
* text for;
|
|
200
223
|
* _len counts triples. A declared teaching replaces the baseline human line as field 0;
|
|
201
224
|
* a declared remediation becomes the optional fourth field. */
|
|
202
225
|
extern const char *const scr_library_trap_overlays[];
|
|
@@ -1001,7 +1024,7 @@ ScrStr *scr_arr_join(ScrArr *a, ScrStr *sep);
|
|
|
1001
1024
|
ScrStr *scr_str_raw(ScrArr *raw, ScrArr *subs);
|
|
1002
1025
|
|
|
1003
1026
|
/* ── regular expressions (scr_regex.c — linked ONLY when the program
|
|
1004
|
-
* contains a regex literal; see
|
|
1027
|
+
* contains a regex literal; see native-toolchain.ts) ────────────────────────────────
|
|
1005
1028
|
* The engine is quickjs-ng's libregexp (the same bytecode interpreter the
|
|
1006
1029
|
* dynamic island uses), compiled standalone. A ScrRegex is today ALWAYS an
|
|
1007
1030
|
* immortal interned literal: the compiler emits one static per distinct
|
|
@@ -4368,7 +4391,7 @@ void scr_island_set_fetch(void (*boot)(void *jsctx), bool (*pending)(void),
|
|
|
4368
4391
|
|
|
4369
4392
|
/* ── the island's node:http/https client bridge (scr_net_island.c) ────
|
|
4370
4393
|
* The one TU referencing BOTH the socket units and the island (the
|
|
4371
|
-
* scr_zlib_island.c precedent):
|
|
4394
|
+
* scr_zlib_island.c precedent): native-toolchain.ts compiles it exactly when a
|
|
4372
4395
|
* --dynamic build links the socket units, and the emitted main calls
|
|
4373
4396
|
* scr_net_island_install before any island entry. `attach` runs while
|
|
4374
4397
|
* the island builds its bootstrap host object (jsctx and host_obj are
|
|
@@ -5064,7 +5087,7 @@ ScrBytes *scr_bytes_concat_len(const ScrArr *list, double total);
|
|
|
5064
5087
|
ScrBytes *scr_bytes_concat(const ScrArr *list); /* +1 */
|
|
5065
5088
|
|
|
5066
5089
|
/* ── util.inspect (scr_inspect.c — linked ONLY when the program calls
|
|
5067
|
-
* util.inspect/format; see
|
|
5090
|
+
* util.inspect/format; see native-toolchain.ts) ─────────────────────────────────────
|
|
5068
5091
|
* The runtime half of the static inspect rendering: the compiler
|
|
5069
5092
|
* synthesizes one traversal helper per static type; these entries own
|
|
5070
5093
|
* Node's exact scalar formatting and the layout engine (frames,
|
|
@@ -5176,7 +5199,7 @@ bool scr_process_stderr_write_bytes(const ScrBytes *b, const ScrStr *encoding);
|
|
|
5176
5199
|
void scr_fs_throw(int e, const char *op, const ScrStr *path);
|
|
5177
5200
|
|
|
5178
5201
|
/* ── zlib (scr_zlib.c — compiled and linked with -lz only when the
|
|
5179
|
-
* program uses zlib, like scr_regex.c/libregexp; see
|
|
5202
|
+
* program uses zlib, like scr_regex.c/libregexp; see native-toolchain.ts) ──────────
|
|
5180
5203
|
* deflateSync/inflateSync over u8 bytes with Node's default options
|
|
5181
5204
|
* (zlib format, default level/windowBits). deflate never throws (OOM
|
|
5182
5205
|
* aborts); inflate of corrupt input THROWS Node's error catchably
|
|
@@ -5191,7 +5214,7 @@ ScrBytes *scr_zlib_inflate_mode(const ScrBytes *data, double mode);
|
|
|
5191
5214
|
void scr_zlib_island_install(void);
|
|
5192
5215
|
|
|
5193
5216
|
/* ── node:net (scr_net.c — compiled and linked ONLY when the program
|
|
5194
|
-
* uses the net surface, like scr_events.c; see
|
|
5217
|
+
* uses the net surface, like scr_events.c; see native-toolchain.ts) ─────────────────
|
|
5195
5218
|
* TCP servers and sockets over the unit's own readiness poller
|
|
5196
5219
|
* (scr_platform.h: kqueue on macOS/BSD, epoll on Linux): refcounted handles
|
|
5197
5220
|
* whose listeners MOVE in and drop at settlement (the ScrChild ownership
|
|
@@ -5294,10 +5317,18 @@ void scr_net_sock_release_v(void *p);
|
|
|
5294
5317
|
|
|
5295
5318
|
ScrNetServer *scr_net_create_server(ScrClosure *handler /*moves, nullable*/, ScrNetConnFn fn); /* +1 */
|
|
5296
5319
|
void scr_net_listen(ScrNetServer *s, double port, ScrClosure *cb /*moves, nullable*/);
|
|
5297
|
-
/* listen({ port, host, ipv6Only }): host is an IP literal ("" =
|
|
5298
|
-
* dual-stack any default); ipv6Only sets IPV6_V6ONLY before the bind.
|
|
5320
|
+
/* listen({ port, host, ipv6Only, reusePort }): host is an IP literal ("" =
|
|
5321
|
+
* the dual-stack any default); ipv6Only sets IPV6_V6ONLY before the bind.
|
|
5322
|
+
* The old entry point ignores reusePort and is retained for old IR. */
|
|
5299
5323
|
void scr_net_listen_opts(ScrNetServer *s, double port, ScrStr *host /*borrowed*/,
|
|
5300
5324
|
bool ipv6_only, ScrClosure *cb /*moves, nullable*/);
|
|
5325
|
+
/* Additive ABI for listen({ port, host, ipv6Only, reusePort }): reuse_port
|
|
5326
|
+
* requests the platform matrix documented in scr_net.c. Unsupported
|
|
5327
|
+
* platforms and kernels fail asynchronously; they never fall back to an
|
|
5328
|
+
* ordinary single listener. */
|
|
5329
|
+
void scr_net_listen_opts_reuse_port(ScrNetServer *s, double port, ScrStr *host /*borrowed*/,
|
|
5330
|
+
bool ipv6_only, bool reuse_port,
|
|
5331
|
+
ScrClosure *cb /*moves, nullable*/);
|
|
5301
5332
|
double scr_net_server_port(ScrNetServer *s); /* address().port */
|
|
5302
5333
|
/* Writable http.Server timeout property storage. `field` is the compiler
|
|
5303
5334
|
* ABI selector: timeout, keepAliveTimeout, headersTimeout, requestTimeout,
|
|
@@ -5594,7 +5625,7 @@ long scr_secure_ctx_live_count(void);
|
|
|
5594
5625
|
|
|
5595
5626
|
/* ── node:tls, the CA-store introspection slice (scr_tls_ca.c — its own
|
|
5596
5627
|
* unit and link gate; NO mbedTLS, so a getCACertificates-only binary never
|
|
5597
|
-
* builds the archive;
|
|
5628
|
+
* builds the archive; native-toolchain.ts also compiles it whenever scr_tls.c does). The
|
|
5598
5629
|
* HOST roots (Windows' system certificate stores, the established bundle probe on
|
|
5599
5630
|
* POSIX) stand in for both Node's compiled-in Mozilla roots ('bundled',
|
|
5600
5631
|
* rootCertificates) and the platform store ('system') — the established
|
package/src/scr_string.c
CHANGED
|
@@ -83,12 +83,12 @@ ScrStr *scr_str_new(const char *bytes, size_t len) {
|
|
|
83
83
|
return s;
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
/* One-slot free-block cache for
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
86
|
+
/* One-slot free-block cache for concat callers that must copy: observable
|
|
87
|
+
* aliases, `s = s + s`, and non-canonical concat shapes still allocate a
|
|
88
|
+
* replacement result. The compiler's canonical self-assignment handoff
|
|
89
|
+
* leaves its left snapshot uniquely owned, so it instead uses the in-place
|
|
90
|
+
* path below; this cache remains useful for the copy cases. Disabled in the
|
|
91
|
+
* audit lane so ASan sees every logical free as a real free. */
|
|
92
92
|
#ifndef SCR_RC_AUDIT
|
|
93
93
|
static SCR_TL ScrStr *scr_str_spare;
|
|
94
94
|
#endif
|
|
@@ -166,12 +166,11 @@ ScrStr *scr_str_concat(ScrStr *a, ScrStr *b) {
|
|
|
166
166
|
a->rc = 2; /* +1 for the returned reference, beside the caller's borrow */
|
|
167
167
|
return a;
|
|
168
168
|
}
|
|
169
|
-
/* Copy path. Geometric slack keeps
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* iteration's slightly-larger allocation). */
|
|
169
|
+
/* Copy path. Geometric slack keeps uniquely-owned concat chains and the
|
|
170
|
+
* optimized self-assignment handoff amortized when they outgrow capacity.
|
|
171
|
+
* Aliases and `s = s + s` deliberately arrive with rc > 1 and stay on this
|
|
172
|
+
* path, preserving string immutability; their sizable replacement results
|
|
173
|
+
* can still benefit from the spare-block cache above. */
|
|
175
174
|
size_t newcap = newlen;
|
|
176
175
|
if (a->rc == 1) {
|
|
177
176
|
size_t grown = a->cap + (a->cap >> 1) + 16;
|
package/src/scr_test.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* node:test — the in-process test runner (linked only when the program
|
|
2
|
-
* imports node:test;
|
|
2
|
+
* imports node:test; native-toolchain.ts gates on moduleUsesNodeTest like dgram/net).
|
|
3
3
|
*
|
|
4
4
|
* Registration (test/it/describe/suite/hooks) builds a tree under an
|
|
5
5
|
* implicit root while the module bodies run: describe callbacks execute
|
package/src/scr_tls_ca.c
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* of mbedTLS: everything here is PEM-BLOCK bookkeeping over the host
|
|
5
5
|
* roots (plus crypt32 store access on Windows), so a program that only
|
|
6
6
|
* inspects the CA store never builds the TLS archive. scr_tls.c (when it
|
|
7
|
-
* links —
|
|
7
|
+
* links — native-toolchain.ts compiles this unit alongside it) consults
|
|
8
8
|
* scr_tls_ca_default_override for its client trust anchors, which is what
|
|
9
9
|
* makes setDefaultCACertificates LIVE semantics: the next https/tls dial
|
|
10
10
|
* verifies against the replaced set.
|
package/src/scr_win.c
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* win32 libc shims — the POSIX/BSD functions the runtime calls that
|
|
2
2
|
* mingw-w64's CRT does not provide (declared in scr_runtime.h's _WIN32
|
|
3
|
-
* block). Compiled into win32-target builds only (
|
|
3
|
+
* block). Compiled into win32-target builds only (native-toolchain.ts adds this TU and
|
|
4
4
|
* -ladvapi32 for windows triples); an empty TU anywhere else, so POSIX
|
|
5
5
|
* builds cannot change by a byte. */
|
|
6
6
|
#ifdef _WIN32
|
|
@@ -69,7 +69,7 @@ char *strcasestr(const char *hay, const char *needle) {
|
|
|
69
69
|
|
|
70
70
|
#else /* !_WIN32 */
|
|
71
71
|
|
|
72
|
-
/* Empty TU off-Windows:
|
|
72
|
+
/* Empty TU off-Windows: native-toolchain.ts only compiles this file for windows triples,
|
|
73
73
|
* but an accidental link elsewhere must stay harmless. */
|
|
74
74
|
typedef int scr_win_unused;
|
|
75
75
|
|
package/src/scr_zlib.c
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/* node:zlib, the lowered slice: deflateSync/inflateSync over u8 bytes with
|
|
2
2
|
* Node's DEFAULT options (zlib format, Z_DEFAULT_COMPRESSION, windowBits
|
|
3
|
-
* 15). Compiled ONLY when the program uses zlib (
|
|
3
|
+
* 15). Compiled ONLY when the program uses zlib (native-toolchain.ts gates it exactly
|
|
4
4
|
* like scr_regex.c/libregexp), so zlib-free binaries keep their
|
|
5
5
|
* historical link line. Host builds link the system -lz; cross targets
|
|
6
|
-
* link the vendored zlib built per target (ensureZlibObjects in
|
|
6
|
+
* link the vendored zlib built per target (ensureZlibObjects in native-toolchain.ts).
|
|
7
7
|
*
|
|
8
8
|
* Compressed OUTPUT bytes are zlib-version-dependent — the differential
|
|
9
9
|
* corpus tests round-trips and fixed-blob inflation, never raw deflate
|
package/src/scr_zlib_island.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* The zlib ↔ island bridge — the one translation unit referencing BOTH
|
|
2
|
-
* scr_zlib.c and the island (the scr_inspect_island.c precedent):
|
|
2
|
+
* scr_zlib.c and the island (the scr_inspect_island.c precedent): native-toolchain.ts
|
|
3
3
|
* compiles it exactly when a --dynamic build's embedded npm graph
|
|
4
4
|
* imports node:zlib, and the emitted main calls scr_zlib_island_install
|
|
5
5
|
* before any island entry. zlib-free dynamic builds keep the island's
|
package/vendor/README.md
CHANGED
|
@@ -35,7 +35,7 @@ The engine archive (libqjs.a) is prebuilt best-effort during npm installation (o
|
|
|
35
35
|
- Version: 1.3.1 (release tarball zlib-1.3.1.tar.gz, sha256 9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23)
|
|
36
36
|
- License: zlib (see zlib/LICENSE)
|
|
37
37
|
|
|
38
|
-
The CROSS-target arm of node:zlib (see packages/runtime/src/scr_zlib.c): host builds keep the historical system `-lz` link (macOS ships libz), but zig's cross sysroots have no libz, so SCRIPTC_TARGET builds compile this vendored copy per target instead. Only the flat `*.c`/`*.h` at the distribution root are vendored (LICENSE beside them) — contrib, tests, build machinery, and docs are not. No vendored file is modified; the gz* file-I/O TUs are vendored for faithfulness but never compiled (nothing references the gzFile API — see ZLIB_SOURCES in packages/compiler/src/backend/
|
|
38
|
+
The CROSS-target arm of node:zlib (see packages/runtime/src/scr_zlib.c): host builds keep the historical system `-lz` link (macOS ships libz), but zig's cross sysroots have no libz, so SCRIPTC_TARGET builds compile this vendored copy per target instead. Only the flat `*.c`/`*.h` at the distribution root are vendored (LICENSE beside them) — contrib, tests, build machinery, and docs are not. No vendored file is modified; the gz* file-I/O TUs are vendored for faithfulness but never compiled (nothing references the gzFile API — see ZLIB_SOURCES in packages/compiler/src/backend/vendor-archives.ts). To update, re-fetch the release tarball, copy the same flat set, and bump `ZLIB_VERSION` in vendor-archives.ts.
|
|
39
39
|
|
|
40
40
|
The objects build lazily on the first zlib-using cross compile into the per-user build cache's `vendor/zlib-<version>-<flavor>-<target>-<toolchain>/` directory — one flavor per driver/target and compiler environment/identity (the lre-objects pattern). Zlib-free binaries never compile any of this; compressed OUTPUT bytes are zlib-version-dependent, which is why the corpus only compares round-trips and fixed-blob inflation.
|
|
41
41
|
|
|
@@ -45,7 +45,7 @@ The objects build lazily on the first zlib-using cross compile into the per-user
|
|
|
45
45
|
- Version: 7.88.1 (headers copied byte-for-byte from `node:24.15.0-bookworm`'s `/usr/include/aarch64-linux-gnu/curl/`; the arch-specific include dir is Debian multiarch layout — the headers themselves are architecture-independent, `system.h` selects per-arch typedefs at preprocessing time)
|
|
46
46
|
- License: curl (see curl/COPYRIGHT — the Debian machine-readable copyright file for the package the headers came from)
|
|
47
47
|
|
|
48
|
-
HEADERS ONLY — no curl C source is vendored and none is ever compiled. These headers now serve ONLY the RETIRED curl reference implementation of fetch (packages/runtime/src/scr_fetch_curl.c, selected by `SCRIPTC_FETCH_CURL=1`; kept compilable for one release as the native flip's reference — see scr_fetch.c, the default, which rides scr_net/scr_tls/scr_http/zlib and touches nothing here). Under the flag: host builds link the system `-lcurl` (macOS ships libcurl), and linux-gnu CROSS builds compile scr_fetch_curl.c against these headers, then link against a generated STUB `libcurl.so` (soname `libcurl.so.4`, empty definitions of exactly the symbols scr_fetch_curl.c calls — see CURL_STUB_SYMBOLS in packages/compiler/src/backend/
|
|
48
|
+
HEADERS ONLY — no curl C source is vendored and none is ever compiled. These headers now serve ONLY the RETIRED curl reference implementation of fetch (packages/runtime/src/scr_fetch_curl.c, selected by `SCRIPTC_FETCH_CURL=1`; kept compilable for one release as the native flip's reference — see scr_fetch.c, the default, which rides scr_net/scr_tls/scr_http/zlib and touches nothing here). Under the flag: host builds link the system `-lcurl` (macOS ships libcurl), and linux-gnu CROSS builds compile scr_fetch_curl.c against these headers, then link against a generated STUB `libcurl.so` (soname `libcurl.so.4`, empty definitions of exactly the symbols scr_fetch_curl.c calls — see CURL_STUB_SYMBOLS in packages/compiler/src/backend/vendor-archives.ts) so the produced binary records a plain `DT_NEEDED libcurl.so.4` that the TARGET system's real libcurl satisfies at load time, the standard cross-link import-stub technique. The 7.88.1 pin is a floor, not a lock: scr_fetch_curl.c's newest requirement is CURLOPT_PROTOCOLS_STR (7.85.0) and the unversioned symbol references bind to any libcurl.so.4. This whole directory leaves with scr_fetch_curl.c when the reference retires for good.
|
|
49
49
|
|
|
50
50
|
The stub builds lazily on the first flag-selected fetch cross compile into the per-user build cache's `vendor/curl-stub-<target>-<toolchain>/` directory (the zlib-objects pattern). Default builds never see any of this, and no build ever compiles curl itself.
|
|
51
51
|
|
|
@@ -55,6 +55,6 @@ The stub builds lazily on the first flag-selected fetch cross compile into the p
|
|
|
55
55
|
- Version: mbedtls-3.6.7 (the 3.6 LTS line — 4.x moved the crypto core into the separate TF-PSA-Crypto repository; the self-contained LTS is what a vendored tree wants)
|
|
56
56
|
- License: Apache-2.0 (see mbedtls/LICENSE)
|
|
57
57
|
|
|
58
|
-
The TLS provider behind node:tls/node:https (see the design note atop packages/runtime/src/scr_tls.c for why mbedTLS over SecureTransport/BoringSSL/libtls). Only `include/` and `library/` are vendored (LICENSE beside them) — tests, docs, programs, scripts, and CMake machinery are not. No vendored file is modified and no custom config is applied (the stock `mbedtls_config.h` builds every `library/*.c` standalone with clang); to update, re-fetch the release tarball, copy the same two directories, and bump `MBEDTLS_VERSION` in packages/compiler/src/backend/
|
|
58
|
+
The TLS provider behind node:tls/node:https (see the design note atop packages/runtime/src/scr_tls.c for why mbedTLS over SecureTransport/BoringSSL/libtls). Only `include/` and `library/` are vendored (LICENSE beside them) — tests, docs, programs, scripts, and CMake machinery are not. No vendored file is modified and no custom config is applied (the stock `mbedtls_config.h` builds every `library/*.c` standalone with clang); to update, re-fetch the release tarball, copy the same two directories, and bump `MBEDTLS_VERSION` in packages/compiler/src/backend/vendor-archives.ts.
|
|
59
59
|
|
|
60
60
|
The archive (libmbedtls.a) is prebuilt best-effort during npm installation (or explicitly by `scriptc cache warm`) and otherwise built lazily on the first TLS-using compile. It lives under the per-user build cache's `vendor/mbedtls-<version>-<flavor>-<target>-<toolchain>/` directory — one flavor per lane (plain, asan), native platform/architecture or explicit cross target, and compiler environment/identity, the libqjs.a pattern. TLS-free binaries never compile or link any of this.
|