@scriptc/runtime 0.0.4 → 0.0.5
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 +1 -1
- package/src/scr_array.c +6 -12
- package/src/scr_assert.c +1 -2
- package/src/scr_bytes.c +3 -6
- package/src/scr_bytes_io.c +1 -2
- package/src/scr_closure.c +1 -2
- package/src/scr_console.c +5 -0
- package/src/scr_cycle.c +1 -2
- package/src/scr_error.c +2 -4
- package/src/scr_events_emitter.c +1 -2
- package/src/scr_exception.c +87 -2
- package/src/scr_inspect.c +1 -2
- package/src/scr_json.c +11 -20
- package/src/scr_lib.c +50 -66
- package/src/scr_library.c +222 -0
- package/src/scr_map.c +2 -4
- package/src/scr_path.c +4 -8
- package/src/scr_regex.c +16 -25
- package/src/scr_runtime.h +75 -0
- package/src/scr_string.c +2 -4
- package/src/scr_symbol.c +2 -3
- package/src/scr_url.c +9 -16
- package/src/scr_url_params.c +6 -12
- package/src/scr_zlib.c +1 -2
package/src/scr_lib.c
CHANGED
|
@@ -126,11 +126,25 @@ static void scr_lib_cleanup(void) {
|
|
|
126
126
|
scr_versions_openssl_str = NULL;
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
+
#ifndef SCR_LIB
|
|
130
|
+
/* Executable lane only: a library artifact has no argv and registers no
|
|
131
|
+
* atexit handlers (the emitted library init never calls this; keeping it out
|
|
132
|
+
* the archive's objects free of any atexit reference — the K8 ambient
|
|
133
|
+
* audit's bar). */
|
|
129
134
|
void scr_lib_init(int argc, char **argv) {
|
|
130
135
|
scr_lib_argc = argc;
|
|
131
136
|
scr_lib_argv = argv;
|
|
132
137
|
atexit(scr_lib_cleanup);
|
|
133
138
|
}
|
|
139
|
+
#endif /* !SCR_LIB */
|
|
140
|
+
|
|
141
|
+
#ifdef SCR_LIB
|
|
142
|
+
/* Library builds never call scr_lib_init (a library artifact has no argv and registers no
|
|
143
|
+
* atexit handlers); the interned process values above still intern lazily
|
|
144
|
+
* on first read, so the library reset seam releases them here instead —
|
|
145
|
+
* scr_library_reset (scr_library.c) calls this every session reset. */
|
|
146
|
+
void scr_lib_session_cleanup(void) { scr_lib_cleanup(); }
|
|
147
|
+
#endif
|
|
134
148
|
|
|
135
149
|
/* Raw argv accessors for the island's process shim (scr_island.c): the
|
|
136
150
|
* island's process.argv must match the static world's ["scriptc",
|
|
@@ -261,8 +275,7 @@ ScrStr *scr_env_get(const ScrStr *name) {
|
|
|
261
275
|
if (need == 0) return NULL; /* absent (an empty value still needs its NUL) */
|
|
262
276
|
char *buf = malloc(need);
|
|
263
277
|
if (!buf) {
|
|
264
|
-
|
|
265
|
-
abort();
|
|
278
|
+
scr_trap("scriptc: out of memory\n");
|
|
266
279
|
}
|
|
267
280
|
DWORD got = GetEnvironmentVariableA(name->data, buf, need);
|
|
268
281
|
ScrStr *s = scr_str_new(buf, got);
|
|
@@ -553,8 +566,7 @@ bool scr_process_kill_named(double pid, const ScrStr *signal) {
|
|
|
553
566
|
size_t cap = 16 + signal->len + 1;
|
|
554
567
|
char *msg = malloc(cap);
|
|
555
568
|
if (!msg) {
|
|
556
|
-
|
|
557
|
-
abort();
|
|
569
|
+
scr_trap("scriptc: out of memory\n");
|
|
558
570
|
}
|
|
559
571
|
int len = snprintf(msg, cap, "Unknown signal: %s", signal->data);
|
|
560
572
|
scr_throw_error_msg(SCR_ERR_TYPE, msg, (size_t)len);
|
|
@@ -567,8 +579,7 @@ bool scr_process_kill_named(double pid, const ScrStr *signal) {
|
|
|
567
579
|
ScrStr *scr_process_cwd(void) {
|
|
568
580
|
char buf[4096];
|
|
569
581
|
if (!getcwd(buf, sizeof buf)) {
|
|
570
|
-
|
|
571
|
-
abort();
|
|
582
|
+
scr_trap("scriptc: process.cwd() failed\n");
|
|
572
583
|
}
|
|
573
584
|
return scr_str_new(buf, strlen(buf));
|
|
574
585
|
}
|
|
@@ -612,16 +623,14 @@ bool scr_proc_stream_write(double fd, const ScrStr *data) {
|
|
|
612
623
|
ScrStr *scr_os_homedir(void) {
|
|
613
624
|
const char *home = getenv("USERPROFILE");
|
|
614
625
|
if (home && home[0] != '\0') return scr_str_new(home, strlen(home));
|
|
615
|
-
|
|
616
|
-
abort();
|
|
626
|
+
scr_trap("scriptc: os.homedir() failed\n");
|
|
617
627
|
}
|
|
618
628
|
|
|
619
629
|
ScrStr *scr_os_user_name(void) {
|
|
620
630
|
char buf[UNLEN + 1];
|
|
621
631
|
DWORD n = sizeof buf;
|
|
622
632
|
if (!GetUserNameA(buf, &n) || n == 0) {
|
|
623
|
-
|
|
624
|
-
abort();
|
|
633
|
+
scr_trap("scriptc: os.userInfo() failed\n");
|
|
625
634
|
}
|
|
626
635
|
return scr_str_new(buf, n - 1); /* n counts the NUL */
|
|
627
636
|
}
|
|
@@ -648,8 +657,7 @@ ScrStr *scr_os_release(void) {
|
|
|
648
657
|
RtlGetVersionFn fn =
|
|
649
658
|
ntdll ? (RtlGetVersionFn)(void *)GetProcAddress(ntdll, "RtlGetVersion") : NULL;
|
|
650
659
|
if (fn == NULL || fn(&info) != 0) {
|
|
651
|
-
|
|
652
|
-
abort();
|
|
660
|
+
scr_trap("scriptc: os.release() failed\n");
|
|
653
661
|
}
|
|
654
662
|
char buf[64];
|
|
655
663
|
int len = snprintf(buf, sizeof buf, "%lu.%lu.%lu", (unsigned long)info.dwMajorVersion,
|
|
@@ -676,8 +684,7 @@ ScrStr *scr_os_tmpdir(void) {
|
|
|
676
684
|
char buf[MAX_PATH + 2];
|
|
677
685
|
DWORD n = GetTempPathA(sizeof buf, buf);
|
|
678
686
|
if (n == 0 || n >= sizeof buf) {
|
|
679
|
-
|
|
680
|
-
abort();
|
|
687
|
+
scr_trap("scriptc: os.tmpdir() failed\n");
|
|
681
688
|
}
|
|
682
689
|
size_t len = n;
|
|
683
690
|
if (len > 1 && (buf[len - 1] == '\\' || buf[len - 1] == '/')) len--;
|
|
@@ -693,8 +700,7 @@ ScrStr *scr_os_homedir(void) {
|
|
|
693
700
|
struct passwd *result = NULL;
|
|
694
701
|
char buf[8192];
|
|
695
702
|
if (getpwuid_r(getuid(), &pw, buf, sizeof buf, &result) != 0 || !result || !result->pw_dir) {
|
|
696
|
-
|
|
697
|
-
abort();
|
|
703
|
+
scr_trap("scriptc: os.homedir() failed\n");
|
|
698
704
|
}
|
|
699
705
|
return scr_str_new(result->pw_dir, strlen(result->pw_dir));
|
|
700
706
|
}
|
|
@@ -706,8 +712,7 @@ ScrStr *scr_os_homedir(void) {
|
|
|
706
712
|
static const struct passwd *scr_os_passwd(char *buf, size_t cap, struct passwd *pw) {
|
|
707
713
|
struct passwd *result = NULL;
|
|
708
714
|
if (getpwuid_r(getuid(), pw, buf, cap, &result) != 0 || !result) {
|
|
709
|
-
|
|
710
|
-
abort();
|
|
715
|
+
scr_trap("scriptc: os.userInfo() failed\n");
|
|
711
716
|
}
|
|
712
717
|
return result;
|
|
713
718
|
}
|
|
@@ -740,8 +745,7 @@ ScrStr *scr_os_release(void) {
|
|
|
740
745
|
/* uname(2)'s release field — Node's uv_os_uname()-backed answer. */
|
|
741
746
|
struct utsname u;
|
|
742
747
|
if (uname(&u) != 0) {
|
|
743
|
-
|
|
744
|
-
abort();
|
|
748
|
+
scr_trap("scriptc: os.release() failed\n");
|
|
745
749
|
}
|
|
746
750
|
return scr_str_new(u.release, strlen(u.release));
|
|
747
751
|
}
|
|
@@ -750,8 +754,7 @@ ScrStr *scr_os_type(void) {
|
|
|
750
754
|
/* uname(2)'s sysname field ("Darwin", "Linux") — Node's os.type(). */
|
|
751
755
|
struct utsname u;
|
|
752
756
|
if (uname(&u) != 0) {
|
|
753
|
-
|
|
754
|
-
abort();
|
|
757
|
+
scr_trap("scriptc: os.type() failed\n");
|
|
755
758
|
}
|
|
756
759
|
return scr_str_new(u.sysname, strlen(u.sysname));
|
|
757
760
|
}
|
|
@@ -824,20 +827,20 @@ struct ScrIfaddrs {
|
|
|
824
827
|
* stance. */
|
|
825
828
|
ScrIfaddrs *scr_os_ifaddrs(void) {
|
|
826
829
|
ScrIfaddrs *s = calloc(1, sizeof *s);
|
|
827
|
-
if (!s)
|
|
830
|
+
if (!s) scr_trap("scriptc: out of memory\n");
|
|
828
831
|
ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
|
|
829
832
|
GAA_FLAG_SKIP_DNS_SERVER;
|
|
830
833
|
ULONG size = 16 * 1024;
|
|
831
834
|
IP_ADAPTER_ADDRESSES *adapters = NULL;
|
|
832
835
|
for (int tries = 0; tries < 4; tries++) {
|
|
833
836
|
adapters = realloc(adapters, size);
|
|
834
|
-
if (!adapters)
|
|
837
|
+
if (!adapters) scr_trap("scriptc: out of memory\n");
|
|
835
838
|
ULONG rc = GetAdaptersAddresses(AF_UNSPEC, flags, NULL, adapters, &size);
|
|
836
839
|
if (rc == ERROR_SUCCESS) break;
|
|
837
840
|
if (rc != ERROR_BUFFER_OVERFLOW) {
|
|
838
841
|
free(adapters);
|
|
839
842
|
s->rows = calloc(1, sizeof *s->rows);
|
|
840
|
-
if (!s->rows)
|
|
843
|
+
if (!s->rows) scr_trap("scriptc: out of memory\n");
|
|
841
844
|
return s; /* empty snapshot */
|
|
842
845
|
}
|
|
843
846
|
}
|
|
@@ -850,7 +853,7 @@ ScrIfaddrs *scr_os_ifaddrs(void) {
|
|
|
850
853
|
}
|
|
851
854
|
}
|
|
852
855
|
s->rows = calloc(count ? count : 1, sizeof *s->rows);
|
|
853
|
-
if (!s->rows)
|
|
856
|
+
if (!s->rows) scr_trap("scriptc: out of memory\n");
|
|
854
857
|
for (IP_ADAPTER_ADDRESSES *a = adapters; a != NULL; a = a->Next) {
|
|
855
858
|
if (a->OperStatus != IfOperStatusUp || a->FirstUnicastAddress == NULL) continue;
|
|
856
859
|
char name[64] = "";
|
|
@@ -934,7 +937,7 @@ static int scr_netmask_prefix(const unsigned char *bytes, size_t len) {
|
|
|
934
937
|
|
|
935
938
|
ScrIfaddrs *scr_os_ifaddrs(void) {
|
|
936
939
|
ScrIfaddrs *s = calloc(1, sizeof *s);
|
|
937
|
-
if (!s)
|
|
940
|
+
if (!s) scr_trap("scriptc: out of memory\n");
|
|
938
941
|
struct ifaddrs *addrs = NULL;
|
|
939
942
|
if (getifaddrs(&addrs) != 0) return s;
|
|
940
943
|
size_t count = 0;
|
|
@@ -942,7 +945,7 @@ ScrIfaddrs *scr_os_ifaddrs(void) {
|
|
|
942
945
|
if (scr_ifaddr_row_ok(ent)) count++;
|
|
943
946
|
}
|
|
944
947
|
s->rows = calloc(count ? count : 1, sizeof *s->rows);
|
|
945
|
-
if (!s->rows)
|
|
948
|
+
if (!s->rows) scr_trap("scriptc: out of memory\n");
|
|
946
949
|
for (struct ifaddrs *ent = addrs; ent != NULL; ent = ent->ifa_next) {
|
|
947
950
|
if (!scr_ifaddr_row_ok(ent)) continue;
|
|
948
951
|
ScrIfaddrRow *row = &s->rows[s->n++];
|
|
@@ -1419,8 +1422,7 @@ void scr_fs_throw(int e, const char *op, const ScrStr *path) {
|
|
|
1419
1422
|
size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown) + 8;
|
|
1420
1423
|
char *msg = malloc(cap);
|
|
1421
1424
|
if (!msg) {
|
|
1422
|
-
|
|
1423
|
-
abort();
|
|
1425
|
+
scr_trap("scriptc: out of memory\n");
|
|
1424
1426
|
}
|
|
1425
1427
|
int len = snprintf(msg, cap, "%s: %s, %s '%s'", name, text, op, shown);
|
|
1426
1428
|
/* A real Error instance (name "Error", message = Node's text) — what a
|
|
@@ -1443,16 +1445,14 @@ ScrStr *scr_fs_read_file(ScrStr *path) {
|
|
|
1443
1445
|
size_t cap = 4096, len = 0;
|
|
1444
1446
|
char *buf = malloc(cap);
|
|
1445
1447
|
if (!buf) {
|
|
1446
|
-
|
|
1447
|
-
abort();
|
|
1448
|
+
scr_trap("scriptc: out of memory\n");
|
|
1448
1449
|
}
|
|
1449
1450
|
for (;;) {
|
|
1450
1451
|
if (cap - len < 2048) {
|
|
1451
1452
|
cap *= 2;
|
|
1452
1453
|
char *grown = realloc(buf, cap);
|
|
1453
1454
|
if (!grown) {
|
|
1454
|
-
|
|
1455
|
-
abort();
|
|
1455
|
+
scr_trap("scriptc: out of memory\n");
|
|
1456
1456
|
}
|
|
1457
1457
|
buf = grown;
|
|
1458
1458
|
}
|
|
@@ -1698,8 +1698,7 @@ static void scr_fs_throw2(int e, const char *op, const ScrStr *src, const ScrStr
|
|
|
1698
1698
|
size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown_src) + strlen(shown_dest) + 16;
|
|
1699
1699
|
char *msg = malloc(cap);
|
|
1700
1700
|
if (!msg) {
|
|
1701
|
-
|
|
1702
|
-
abort();
|
|
1701
|
+
scr_trap("scriptc: out of memory\n");
|
|
1703
1702
|
}
|
|
1704
1703
|
int len = snprintf(msg, cap, "%s: %s, %s '%s' -> '%s'", name, text, op, shown_src, shown_dest);
|
|
1705
1704
|
scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)len, name);
|
|
@@ -1856,8 +1855,7 @@ static void scr_mkdir_rec(char *path, size_t len, mode_t mode) {
|
|
|
1856
1855
|
void scr_fs_mkdir_recursive(ScrStr *path) {
|
|
1857
1856
|
char *buf = malloc(path->len + 1);
|
|
1858
1857
|
if (!buf) {
|
|
1859
|
-
|
|
1860
|
-
abort();
|
|
1858
|
+
scr_trap("scriptc: out of memory\n");
|
|
1861
1859
|
}
|
|
1862
1860
|
memcpy(buf, path->data, path->len + 1); /* ScrStr data is NUL-terminated */
|
|
1863
1861
|
scr_mkdir_rec(buf, path->len, 0777);
|
|
@@ -1869,8 +1867,7 @@ void scr_fs_mkdir_recursive(ScrStr *path) {
|
|
|
1869
1867
|
void scr_fs_mkdir_recursive_mode(ScrStr *path, double mode) {
|
|
1870
1868
|
char *buf = malloc(path->len + 1);
|
|
1871
1869
|
if (!buf) {
|
|
1872
|
-
|
|
1873
|
-
abort();
|
|
1870
|
+
scr_trap("scriptc: out of memory\n");
|
|
1874
1871
|
}
|
|
1875
1872
|
memcpy(buf, path->data, path->len + 1);
|
|
1876
1873
|
scr_mkdir_rec(buf, path->len, (mode_t)mode);
|
|
@@ -1917,8 +1914,7 @@ static void scr_rm_tree_e(const char *path, size_t len, ScrRmFail *f) {
|
|
|
1917
1914
|
size_t namelen = strlen(ent->d_name);
|
|
1918
1915
|
char *child = malloc(len + 1 + namelen + 1);
|
|
1919
1916
|
if (!child) {
|
|
1920
|
-
|
|
1921
|
-
abort();
|
|
1917
|
+
scr_trap("scriptc: out of memory\n");
|
|
1922
1918
|
}
|
|
1923
1919
|
memcpy(child, path, len);
|
|
1924
1920
|
child[len] = '/';
|
|
@@ -2021,8 +2017,7 @@ static char *scr_win_mkdtemp(char *tmpl) {
|
|
|
2021
2017
|
ScrStr *scr_fs_mkdtemp(ScrStr *prefix) {
|
|
2022
2018
|
char *tmpl = malloc(prefix->len + 7);
|
|
2023
2019
|
if (!tmpl) {
|
|
2024
|
-
|
|
2025
|
-
abort();
|
|
2020
|
+
scr_trap("scriptc: out of memory\n");
|
|
2026
2021
|
}
|
|
2027
2022
|
memcpy(tmpl, prefix->data, prefix->len);
|
|
2028
2023
|
memcpy(tmpl + prefix->len, "XXXXXX", 7);
|
|
@@ -2069,16 +2064,14 @@ static char *scr_read_fd_all(double fd, size_t *out_len) {
|
|
|
2069
2064
|
size_t cap = 4096, len = 0;
|
|
2070
2065
|
char *buf = malloc(cap);
|
|
2071
2066
|
if (!buf) {
|
|
2072
|
-
|
|
2073
|
-
abort();
|
|
2067
|
+
scr_trap("scriptc: out of memory\n");
|
|
2074
2068
|
}
|
|
2075
2069
|
for (;;) {
|
|
2076
2070
|
if (cap - len < 2048) {
|
|
2077
2071
|
cap *= 2;
|
|
2078
2072
|
char *grown = realloc(buf, cap);
|
|
2079
2073
|
if (!grown) {
|
|
2080
|
-
|
|
2081
|
-
abort();
|
|
2074
|
+
scr_trap("scriptc: out of memory\n");
|
|
2082
2075
|
}
|
|
2083
2076
|
buf = grown;
|
|
2084
2077
|
}
|
|
@@ -2286,8 +2279,7 @@ double scr_stats_mtime_ms(ScrStats *s) { return s->mtime_ms; }
|
|
|
2286
2279
|
static ScrStats *scr_stats_of(const struct stat *st) {
|
|
2287
2280
|
ScrStats *s = malloc(sizeof(ScrStats));
|
|
2288
2281
|
if (!s) {
|
|
2289
|
-
|
|
2290
|
-
abort();
|
|
2282
|
+
scr_trap("scriptc: out of memory\n");
|
|
2291
2283
|
}
|
|
2292
2284
|
s->rc = 1;
|
|
2293
2285
|
s->is_file = S_ISREG(st->st_mode);
|
|
@@ -2384,16 +2376,14 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
|
|
|
2384
2376
|
}
|
|
2385
2377
|
ScrScandir *s = malloc(sizeof *s);
|
|
2386
2378
|
if (!s) {
|
|
2387
|
-
|
|
2388
|
-
abort();
|
|
2379
|
+
scr_trap("scriptc: out of memory\n");
|
|
2389
2380
|
}
|
|
2390
2381
|
s->len = 0;
|
|
2391
2382
|
s->cap = 8;
|
|
2392
2383
|
s->names = malloc(s->cap * sizeof *s->names);
|
|
2393
2384
|
s->kinds = malloc(s->cap);
|
|
2394
2385
|
if (!s->names || !s->kinds) {
|
|
2395
|
-
|
|
2396
|
-
abort();
|
|
2386
|
+
scr_trap("scriptc: out of memory\n");
|
|
2397
2387
|
}
|
|
2398
2388
|
const struct dirent *ent;
|
|
2399
2389
|
while ((ent = readdir(d)) != NULL) {
|
|
@@ -2434,8 +2424,7 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
|
|
|
2434
2424
|
s->names = realloc(s->names, s->cap * sizeof *s->names);
|
|
2435
2425
|
s->kinds = realloc(s->kinds, s->cap);
|
|
2436
2426
|
if (!s->names || !s->kinds) {
|
|
2437
|
-
|
|
2438
|
-
abort();
|
|
2427
|
+
scr_trap("scriptc: out of memory\n");
|
|
2439
2428
|
}
|
|
2440
2429
|
}
|
|
2441
2430
|
s->names[s->len] = scr_str_new(ent->d_name, strlen(ent->d_name));
|
|
@@ -2545,8 +2534,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2545
2534
|
size_t size = (size_t)n;
|
|
2546
2535
|
unsigned char *bytes = malloc(size ? size : 1);
|
|
2547
2536
|
if (!bytes) {
|
|
2548
|
-
|
|
2549
|
-
abort();
|
|
2537
|
+
scr_trap("scriptc: out of memory\n");
|
|
2550
2538
|
}
|
|
2551
2539
|
arc4random_buf(bytes, size);
|
|
2552
2540
|
ScrStr *out;
|
|
@@ -2554,8 +2542,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2554
2542
|
static const char hex[] = "0123456789abcdef";
|
|
2555
2543
|
char *buf = malloc(size * 2 + 1);
|
|
2556
2544
|
if (!buf) {
|
|
2557
|
-
|
|
2558
|
-
abort();
|
|
2545
|
+
scr_trap("scriptc: out of memory\n");
|
|
2559
2546
|
}
|
|
2560
2547
|
for (size_t i = 0; i < size; i++) {
|
|
2561
2548
|
buf[i * 2] = hex[bytes[i] >> 4];
|
|
@@ -2569,8 +2556,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2569
2556
|
size_t outlen = (size + 2) / 3 * 4;
|
|
2570
2557
|
char *buf = malloc(outlen + 1);
|
|
2571
2558
|
if (!buf) {
|
|
2572
|
-
|
|
2573
|
-
abort();
|
|
2559
|
+
scr_trap("scriptc: out of memory\n");
|
|
2574
2560
|
}
|
|
2575
2561
|
size_t o = 0;
|
|
2576
2562
|
for (size_t i = 0; i < size; i += 3) {
|
|
@@ -2909,8 +2895,7 @@ static bool scr_x509_der(const uint8_t *in, size_t n, const uint8_t **der, size_
|
|
|
2909
2895
|
}
|
|
2910
2896
|
uint8_t *out = malloc(((size_t)(stop - b) / 4 + 1) * 3 + 3);
|
|
2911
2897
|
if (!out) {
|
|
2912
|
-
|
|
2913
|
-
abort();
|
|
2898
|
+
scr_trap("scriptc: out of memory\n");
|
|
2914
2899
|
}
|
|
2915
2900
|
size_t o = 0;
|
|
2916
2901
|
unsigned acc = 0;
|
|
@@ -3126,8 +3111,7 @@ static uint32_t scr_to_uint32(double d);
|
|
|
3126
3111
|
static ScrStr *scr_str_from_units(size_t n, uint32_t (*unit)(void *, size_t), void *src) {
|
|
3127
3112
|
char *out = malloc(n * 3 + 1); /* worst case: 3 bytes per UTF-16 unit */
|
|
3128
3113
|
if (!out) {
|
|
3129
|
-
|
|
3130
|
-
abort();
|
|
3114
|
+
scr_trap("scriptc: out of memory\n");
|
|
3131
3115
|
}
|
|
3132
3116
|
size_t o = 0;
|
|
3133
3117
|
for (size_t i = 0; i < n; i++) {
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/* Library mode support: the panic sink, the poisoned-library flag, the
|
|
2
|
+
* outbound-result arena, the reset registry, and the sink-routing trap
|
|
3
|
+
* funnel. Linked ONLY into library artifacts (every TU of a library archive
|
|
4
|
+
* compiles with -DSCR_LIB); executable builds never contain this file —
|
|
5
|
+
* their funnel expansion lives in scr_console.c and their session teardown
|
|
6
|
+
* stays atexit-driven.
|
|
7
|
+
*
|
|
8
|
+
* The profile-NAMED symbols (init, sink registration, reset, collect) are
|
|
9
|
+
* emitted in the program TU and delegate here, so this file stays
|
|
10
|
+
* profile-agnostic and the program TU carries every profile-named symbol —
|
|
11
|
+
* one place for the conformance symbol audit to look.
|
|
12
|
+
*
|
|
13
|
+
* State after a sink call: none is legal. The trap fired mid-operation with
|
|
14
|
+
* no unwinding — heap, arena, and collector state are unspecified; the library
|
|
15
|
+
* is POISONED. Every runtime-touching entry prologue aborts on the flag
|
|
16
|
+
* (deterministic, never heap corruption); recovery is process restart. */
|
|
17
|
+
#include "scr_runtime.h"
|
|
18
|
+
|
|
19
|
+
#ifdef SCR_LIB
|
|
20
|
+
|
|
21
|
+
#include <stdio.h>
|
|
22
|
+
#include <stdlib.h>
|
|
23
|
+
|
|
24
|
+
/* ── sink registration + poison ───────────────────────────────────────── */
|
|
25
|
+
|
|
26
|
+
static ScrLibSinkFn scr_library_sink = NULL;
|
|
27
|
+
static void *scr_library_sink_ctx = NULL;
|
|
28
|
+
static bool scr_library_poisoned = false;
|
|
29
|
+
|
|
30
|
+
void scr_library_set_sink(ScrLibSinkFn fn, void *ctx) {
|
|
31
|
+
/* Latest registration wins; re-registration is permitted before a trap.
|
|
32
|
+
* Deliberately NOT poison-guarded: a pure store, touching no runtime
|
|
33
|
+
* state — but a poisoned library's entries abort regardless of the sink. */
|
|
34
|
+
scr_library_sink = fn;
|
|
35
|
+
scr_library_sink_ctx = ctx;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ── the trap funnel, library expansion ───────────────────────────────────
|
|
39
|
+
* Poison first (the sink may longjmp to a host frame below the entry — the
|
|
40
|
+
* conforming survival pattern), then deliver exactly once, then abort:
|
|
41
|
+
* before registration, or if the sink returns (the ruled host-contract
|
|
42
|
+
* violation). The address is the funnel frame's return address — the trap
|
|
43
|
+
* site — 0 where the toolchain cannot supply one. */
|
|
44
|
+
|
|
45
|
+
#if defined(__GNUC__) || defined(__clang__)
|
|
46
|
+
#define SCR_TRAP_ADDR() ((uint64_t)(uintptr_t)__builtin_return_address(0))
|
|
47
|
+
#else
|
|
48
|
+
#define SCR_TRAP_ADDR() ((uint64_t)0)
|
|
49
|
+
#endif
|
|
50
|
+
|
|
51
|
+
static _Noreturn void scr_library_trap_deliver(const char *msg, size_t len, uint64_t addr) {
|
|
52
|
+
scr_library_poisoned = true;
|
|
53
|
+
if (scr_library_sink != NULL) {
|
|
54
|
+
scr_library_sink(scr_library_sink_ctx, (const uint8_t *)msg, len, addr);
|
|
55
|
+
}
|
|
56
|
+
abort();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
__attribute__((noinline)) _Noreturn void scr_trap(const char *msg) {
|
|
60
|
+
scr_library_trap_deliver(msg, strlen(msg), SCR_TRAP_ADDR());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
__attribute__((noinline)) _Noreturn void scr_trap_fmt(const char *fmt, ...) {
|
|
64
|
+
static char buf[512]; /* no malloc on the invariant-failure path */
|
|
65
|
+
va_list ap;
|
|
66
|
+
va_start(ap, fmt);
|
|
67
|
+
int n = vsnprintf(buf, sizeof buf, fmt, ap);
|
|
68
|
+
va_end(ap);
|
|
69
|
+
size_t len = n < 0 ? 0 : (size_t)n >= sizeof buf ? sizeof buf - 1 : (size_t)n;
|
|
70
|
+
scr_library_trap_deliver(buf, len, SCR_TRAP_ADDR());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* ── entry prologues ──────────────────────────────────────────────────── */
|
|
74
|
+
|
|
75
|
+
void scr_library_entry(bool reset_arena) {
|
|
76
|
+
/* A poisoned library's entries abort deterministically — never through the
|
|
77
|
+
* sink again (it received its exactly-once message when the trap fired),
|
|
78
|
+
* never into a heap whose invariants already failed. */
|
|
79
|
+
if (scr_library_poisoned) abort();
|
|
80
|
+
if (reset_arena) scr_library_arena_reset();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ── the outbound-result arena ────────────────────────────────────────────
|
|
84
|
+
* Buffer-class results (string/bytes) MOVE in here; the host reads through
|
|
85
|
+
* borrowed pointers until the arena resets (per-entry under the auto
|
|
86
|
+
* posture, host-cycled when the profile declares a reset symbol; init and
|
|
87
|
+
* collect always reset). */
|
|
88
|
+
|
|
89
|
+
typedef struct {
|
|
90
|
+
void *v;
|
|
91
|
+
bool is_str; /* ScrStr vs ScrBytes — picks the release */
|
|
92
|
+
} ScrCoreArenaEnt;
|
|
93
|
+
|
|
94
|
+
static ScrCoreArenaEnt *scr_library_arena = NULL;
|
|
95
|
+
static size_t scr_library_arena_n = 0, scr_library_arena_cap = 0;
|
|
96
|
+
|
|
97
|
+
static void scr_library_arena_keep(void *v, bool is_str) {
|
|
98
|
+
if (scr_library_arena_n == scr_library_arena_cap) {
|
|
99
|
+
scr_library_arena_cap = scr_library_arena_cap ? scr_library_arena_cap * 2 : 16;
|
|
100
|
+
scr_library_arena = realloc(scr_library_arena, scr_library_arena_cap * sizeof *scr_library_arena);
|
|
101
|
+
if (!scr_library_arena) scr_trap("scriptc: out of memory\n");
|
|
102
|
+
}
|
|
103
|
+
scr_library_arena[scr_library_arena_n].v = v;
|
|
104
|
+
scr_library_arena[scr_library_arena_n].is_str = is_str;
|
|
105
|
+
scr_library_arena_n++;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
void scr_library_arena_reset(void) {
|
|
109
|
+
for (size_t i = 0; i < scr_library_arena_n; i++) {
|
|
110
|
+
if (scr_library_arena[i].is_str) scr_str_release((ScrStr *)scr_library_arena[i].v);
|
|
111
|
+
else scr_bytes_release((ScrBytes *)scr_library_arena[i].v);
|
|
112
|
+
}
|
|
113
|
+
scr_library_arena_n = 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void scr_library_collect(void) {
|
|
117
|
+
scr_library_arena_reset();
|
|
118
|
+
scr_collect_cycles();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ── marshalling helpers (both emissions call exactly these) ──────────── */
|
|
122
|
+
|
|
123
|
+
ScrStr *scr_library_str_in(const uint8_t *p, size_t len) {
|
|
124
|
+
/* ptr may be NULL when len is 0 (the contract's empty-buffer form). */
|
|
125
|
+
return scr_str_new(len == 0 ? "" : (const char *)p, len);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
ScrBytes *scr_library_bytes_in(const uint8_t *p, size_t len) {
|
|
129
|
+
ScrBytes *b = scr_bytes_new(SCR_BYTES_U8, (double)len);
|
|
130
|
+
if (b == NULL) {
|
|
131
|
+
/* scr_bytes_new throws only for lengths past 2^53-1 — an impossible
|
|
132
|
+
* host buffer; funnel the contract violation instead of a NULL deref. */
|
|
133
|
+
scr_exc_clear();
|
|
134
|
+
scr_trap("scriptc: library inbound bytes length out of range\n");
|
|
135
|
+
}
|
|
136
|
+
if (len > 0 && p != NULL) memcpy(b->data, p, len);
|
|
137
|
+
return b;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
void scr_library_str_out(ScrStr *s, const uint8_t **out, size_t *out_len) {
|
|
141
|
+
scr_library_arena_keep(s, true);
|
|
142
|
+
*out = (const uint8_t *)s->data; /* NUL-terminated after len (ScrStr layout) */
|
|
143
|
+
*out_len = s->len;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
void scr_library_bytes_out(ScrBytes *b, const uint8_t **out, size_t *out_len) {
|
|
147
|
+
scr_library_arena_keep(b, false);
|
|
148
|
+
*out = b->data; /* elem is always u8 at the boundary (v1 bytes class) */
|
|
149
|
+
*out_len = b->len;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ── the reset registry + session reset ─────────────────────────────────
|
|
153
|
+
* Where an executable's always-linked units atexit() their lazy teardowns,
|
|
154
|
+
* library builds register here (scr_atexit in scr_runtime.h): registered
|
|
155
|
+
* once, drained on EVERY reset — re-registration guards in the units stay
|
|
156
|
+
* satisfied because the entry persists. */
|
|
157
|
+
|
|
158
|
+
#define SCR_LIB_MAX_RESETS 32
|
|
159
|
+
static void (*scr_library_resets[SCR_LIB_MAX_RESETS])(void);
|
|
160
|
+
static size_t scr_library_nresets = 0;
|
|
161
|
+
|
|
162
|
+
void scr_library_register_reset(void (*fn)(void)) {
|
|
163
|
+
for (size_t i = 0; i < scr_library_nresets; i++) {
|
|
164
|
+
if (scr_library_resets[i] == fn) return;
|
|
165
|
+
}
|
|
166
|
+
if (scr_library_nresets == SCR_LIB_MAX_RESETS) {
|
|
167
|
+
scr_trap("scriptc: internal error: library reset registry overflow\n");
|
|
168
|
+
}
|
|
169
|
+
scr_library_resets[scr_library_nresets++] = fn;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
#ifdef SCR_RC_AUDIT
|
|
173
|
+
extern long scr_str_live_count(void); /* scr_string.c */
|
|
174
|
+
extern long scr_arr_live_count(void); /* scr_array.c */
|
|
175
|
+
extern long scr_map_live_count(void); /* scr_map.c */
|
|
176
|
+
extern long scr_box_live_count(void); /* scr_closure.c */
|
|
177
|
+
extern long scr_closure_live_count(void); /* scr_closure.c */
|
|
178
|
+
extern long scr_obj_live_count(void); /* scr_object.c */
|
|
179
|
+
extern long scr_union_live_count(void); /* scr_union.c */
|
|
180
|
+
extern long scr_dyn_live_count(void); /* scr_json.c */
|
|
181
|
+
extern long scr_bytes_live_count(void); /* scr_bytes.c */
|
|
182
|
+
|
|
183
|
+
/* The per-session heap-emptiness assertion (the audit flavor's determinism
|
|
184
|
+
* seam): after a full reset the live counters must all read zero, or the
|
|
185
|
+
* previous session leaked. A failure is a TRAP through the sink — the
|
|
186
|
+
* executable audit's _Exit(99) stays exe-lane-only. */
|
|
187
|
+
static void scr_library_audit_zero(void) {
|
|
188
|
+
long strings = scr_str_live_count(), arrays = scr_arr_live_count(),
|
|
189
|
+
maps = scr_map_live_count(), boxes = scr_box_live_count(),
|
|
190
|
+
closures = scr_closure_live_count(), objects = scr_obj_live_count(),
|
|
191
|
+
unions = scr_union_live_count(), dyns = scr_dyn_live_count(),
|
|
192
|
+
bytes = scr_bytes_live_count();
|
|
193
|
+
if (strings != 0 || arrays != 0 || maps != 0 || boxes != 0 || closures != 0 ||
|
|
194
|
+
objects != 0 || unions != 0 || dyns != 0 || bytes != 0) {
|
|
195
|
+
scr_trap_fmt(
|
|
196
|
+
"scriptc LIBRARY RC AUDIT FAILED: %ld heap string(s), %ld array(s), "
|
|
197
|
+
"%ld map(s), %ld box(es), %ld closure(s), %ld object(s), "
|
|
198
|
+
"%ld union(s), %ld dyn value(s), %ld bytes value(s) live across re-init\n",
|
|
199
|
+
strings, arrays, maps, boxes, closures, objects, unions, dyns, bytes);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
#endif /* SCR_RC_AUDIT */
|
|
203
|
+
|
|
204
|
+
extern void scr_lib_session_cleanup(void); /* scr_lib.c: the interned process values */
|
|
205
|
+
|
|
206
|
+
void scr_library_reset(void) {
|
|
207
|
+
/* Called by the generated init entry AFTER the program TU released and
|
|
208
|
+
* zeroed its globals (run-once guards included) — the same order the
|
|
209
|
+
* executable exit path runs: library cleanup → cycle collection → RC
|
|
210
|
+
* audit. Everything here is re-runnable; the first call is a cheap
|
|
211
|
+
* no-op pass. */
|
|
212
|
+
scr_exc_clear();
|
|
213
|
+
scr_library_arena_reset();
|
|
214
|
+
for (size_t i = 0; i < scr_library_nresets; i++) scr_library_resets[i]();
|
|
215
|
+
scr_lib_session_cleanup();
|
|
216
|
+
scr_collect_cycles();
|
|
217
|
+
#ifdef SCR_RC_AUDIT
|
|
218
|
+
scr_library_audit_zero();
|
|
219
|
+
#endif
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
#endif /* SCR_LIB */
|
package/src/scr_map.c
CHANGED
|
@@ -31,8 +31,7 @@ long scr_map_live_count(void) { return scr_live_maps; }
|
|
|
31
31
|
#define SCR_MAP_EMPTY SIZE_MAX
|
|
32
32
|
|
|
33
33
|
static void scr_map_oom(void) {
|
|
34
|
-
|
|
35
|
-
abort();
|
|
34
|
+
scr_trap("scriptc: out of memory\n");
|
|
36
35
|
}
|
|
37
36
|
|
|
38
37
|
/* ── key normalization + hashing (SameValueZero) ───────────────────────
|
|
@@ -462,8 +461,7 @@ bool scr_map_iter_live(const ScrMap *m, double i) {
|
|
|
462
461
|
|
|
463
462
|
static const ScrMapEntry *scr_map_iter_at(const ScrMap *m, double i) {
|
|
464
463
|
if (!(i >= 0) || i >= (double)m->nentries || !m->entries[(size_t)i].live) {
|
|
465
|
-
|
|
466
|
-
abort();
|
|
464
|
+
scr_trap("scriptc: internal error: map iteration index out of range\n");
|
|
467
465
|
}
|
|
468
466
|
return &m->entries[(size_t)i];
|
|
469
467
|
}
|
package/src/scr_path.c
CHANGED
|
@@ -37,8 +37,7 @@ static void pb_init(PathBuf *b) {
|
|
|
37
37
|
b->len = 0;
|
|
38
38
|
b->data = malloc(b->cap);
|
|
39
39
|
if (!b->data) {
|
|
40
|
-
|
|
41
|
-
abort();
|
|
40
|
+
scr_trap("scriptc: out of memory\n");
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
@@ -47,8 +46,7 @@ static void pb_reserve(PathBuf *b, size_t extra) {
|
|
|
47
46
|
while (b->len + extra > b->cap) b->cap *= 2;
|
|
48
47
|
char *grown = realloc(b->data, b->cap);
|
|
49
48
|
if (!grown) {
|
|
50
|
-
|
|
51
|
-
abort();
|
|
49
|
+
scr_trap("scriptc: out of memory\n");
|
|
52
50
|
}
|
|
53
51
|
b->data = grown;
|
|
54
52
|
}
|
|
@@ -226,8 +224,7 @@ ScrStr *scr_path_join(ScrArr *parts) {
|
|
|
226
224
|
static void scr_path_cwd(PathBuf *out) {
|
|
227
225
|
char buf[4096];
|
|
228
226
|
if (!getcwd(buf, sizeof buf)) {
|
|
229
|
-
|
|
230
|
-
abort();
|
|
227
|
+
scr_trap("scriptc: path.resolve: getcwd failed\n");
|
|
231
228
|
}
|
|
232
229
|
pb_append(out, buf, strlen(buf));
|
|
233
230
|
}
|
|
@@ -984,8 +981,7 @@ ScrStr *scr_path_win32_relative(ScrStr *from, ScrStr *to) {
|
|
|
984
981
|
char *flow = malloc(rfrom->len ? rfrom->len : 1);
|
|
985
982
|
char *tlow = malloc(rto->len ? rto->len : 1);
|
|
986
983
|
if (!flow || !tlow) {
|
|
987
|
-
|
|
988
|
-
abort();
|
|
984
|
+
scr_trap("scriptc: out of memory\n");
|
|
989
985
|
}
|
|
990
986
|
for (size_t k = 0; k < rfrom->len; k++) flow[k] = scr_path_w32_lower(rfrom->data[k]);
|
|
991
987
|
for (size_t k = 0; k < rto->len; k++) tlow[k] = scr_path_w32_lower(rto->data[k]);
|