@scriptc/runtime 0.0.3 → 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_island.c +6 -6
- package/src/scr_json.c +11 -20
- package/src/scr_lib.c +60 -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_qs.c +496 -0
- package/src/scr_regex.c +16 -25
- package/src/scr_runtime.h +136 -0
- package/src/scr_string.c +17 -6
- 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/vendor/mbedtls/library/ecp.c +1 -1
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++];
|
|
@@ -1093,6 +1096,16 @@ double scr_process_uptime(void) {
|
|
|
1093
1096
|
return (scr_uptime_now_ms() - scr_uptime_t0_ms) / 1000.0;
|
|
1094
1097
|
}
|
|
1095
1098
|
|
|
1099
|
+
/* perf_hooks performance.now(): milliseconds since the process's own
|
|
1100
|
+
* start (Node's timeOrigin anchor), fractional — the same monotonic
|
|
1101
|
+
* clock and anchor as uptime, in Node's performance.now units. */
|
|
1102
|
+
double scr_perf_now(void) {
|
|
1103
|
+
#ifdef _WIN32
|
|
1104
|
+
if (scr_uptime_t0_ms == 0) scr_uptime_anchor_init();
|
|
1105
|
+
#endif
|
|
1106
|
+
return scr_uptime_now_ms() - scr_uptime_t0_ms;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1096
1109
|
#ifdef _WIN32
|
|
1097
1110
|
/* GetProcessTimes/GetThreadTimes answer 100ns units; Node reports µs. */
|
|
1098
1111
|
static double scr_filetime_us(FILETIME ft) {
|
|
@@ -1409,8 +1422,7 @@ void scr_fs_throw(int e, const char *op, const ScrStr *path) {
|
|
|
1409
1422
|
size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown) + 8;
|
|
1410
1423
|
char *msg = malloc(cap);
|
|
1411
1424
|
if (!msg) {
|
|
1412
|
-
|
|
1413
|
-
abort();
|
|
1425
|
+
scr_trap("scriptc: out of memory\n");
|
|
1414
1426
|
}
|
|
1415
1427
|
int len = snprintf(msg, cap, "%s: %s, %s '%s'", name, text, op, shown);
|
|
1416
1428
|
/* A real Error instance (name "Error", message = Node's text) — what a
|
|
@@ -1433,16 +1445,14 @@ ScrStr *scr_fs_read_file(ScrStr *path) {
|
|
|
1433
1445
|
size_t cap = 4096, len = 0;
|
|
1434
1446
|
char *buf = malloc(cap);
|
|
1435
1447
|
if (!buf) {
|
|
1436
|
-
|
|
1437
|
-
abort();
|
|
1448
|
+
scr_trap("scriptc: out of memory\n");
|
|
1438
1449
|
}
|
|
1439
1450
|
for (;;) {
|
|
1440
1451
|
if (cap - len < 2048) {
|
|
1441
1452
|
cap *= 2;
|
|
1442
1453
|
char *grown = realloc(buf, cap);
|
|
1443
1454
|
if (!grown) {
|
|
1444
|
-
|
|
1445
|
-
abort();
|
|
1455
|
+
scr_trap("scriptc: out of memory\n");
|
|
1446
1456
|
}
|
|
1447
1457
|
buf = grown;
|
|
1448
1458
|
}
|
|
@@ -1688,8 +1698,7 @@ static void scr_fs_throw2(int e, const char *op, const ScrStr *src, const ScrStr
|
|
|
1688
1698
|
size_t cap = strlen(name) + strlen(text) + strlen(op) + strlen(shown_src) + strlen(shown_dest) + 16;
|
|
1689
1699
|
char *msg = malloc(cap);
|
|
1690
1700
|
if (!msg) {
|
|
1691
|
-
|
|
1692
|
-
abort();
|
|
1701
|
+
scr_trap("scriptc: out of memory\n");
|
|
1693
1702
|
}
|
|
1694
1703
|
int len = snprintf(msg, cap, "%s: %s, %s '%s' -> '%s'", name, text, op, shown_src, shown_dest);
|
|
1695
1704
|
scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)len, name);
|
|
@@ -1846,8 +1855,7 @@ static void scr_mkdir_rec(char *path, size_t len, mode_t mode) {
|
|
|
1846
1855
|
void scr_fs_mkdir_recursive(ScrStr *path) {
|
|
1847
1856
|
char *buf = malloc(path->len + 1);
|
|
1848
1857
|
if (!buf) {
|
|
1849
|
-
|
|
1850
|
-
abort();
|
|
1858
|
+
scr_trap("scriptc: out of memory\n");
|
|
1851
1859
|
}
|
|
1852
1860
|
memcpy(buf, path->data, path->len + 1); /* ScrStr data is NUL-terminated */
|
|
1853
1861
|
scr_mkdir_rec(buf, path->len, 0777);
|
|
@@ -1859,8 +1867,7 @@ void scr_fs_mkdir_recursive(ScrStr *path) {
|
|
|
1859
1867
|
void scr_fs_mkdir_recursive_mode(ScrStr *path, double mode) {
|
|
1860
1868
|
char *buf = malloc(path->len + 1);
|
|
1861
1869
|
if (!buf) {
|
|
1862
|
-
|
|
1863
|
-
abort();
|
|
1870
|
+
scr_trap("scriptc: out of memory\n");
|
|
1864
1871
|
}
|
|
1865
1872
|
memcpy(buf, path->data, path->len + 1);
|
|
1866
1873
|
scr_mkdir_rec(buf, path->len, (mode_t)mode);
|
|
@@ -1907,8 +1914,7 @@ static void scr_rm_tree_e(const char *path, size_t len, ScrRmFail *f) {
|
|
|
1907
1914
|
size_t namelen = strlen(ent->d_name);
|
|
1908
1915
|
char *child = malloc(len + 1 + namelen + 1);
|
|
1909
1916
|
if (!child) {
|
|
1910
|
-
|
|
1911
|
-
abort();
|
|
1917
|
+
scr_trap("scriptc: out of memory\n");
|
|
1912
1918
|
}
|
|
1913
1919
|
memcpy(child, path, len);
|
|
1914
1920
|
child[len] = '/';
|
|
@@ -2011,8 +2017,7 @@ static char *scr_win_mkdtemp(char *tmpl) {
|
|
|
2011
2017
|
ScrStr *scr_fs_mkdtemp(ScrStr *prefix) {
|
|
2012
2018
|
char *tmpl = malloc(prefix->len + 7);
|
|
2013
2019
|
if (!tmpl) {
|
|
2014
|
-
|
|
2015
|
-
abort();
|
|
2020
|
+
scr_trap("scriptc: out of memory\n");
|
|
2016
2021
|
}
|
|
2017
2022
|
memcpy(tmpl, prefix->data, prefix->len);
|
|
2018
2023
|
memcpy(tmpl + prefix->len, "XXXXXX", 7);
|
|
@@ -2059,16 +2064,14 @@ static char *scr_read_fd_all(double fd, size_t *out_len) {
|
|
|
2059
2064
|
size_t cap = 4096, len = 0;
|
|
2060
2065
|
char *buf = malloc(cap);
|
|
2061
2066
|
if (!buf) {
|
|
2062
|
-
|
|
2063
|
-
abort();
|
|
2067
|
+
scr_trap("scriptc: out of memory\n");
|
|
2064
2068
|
}
|
|
2065
2069
|
for (;;) {
|
|
2066
2070
|
if (cap - len < 2048) {
|
|
2067
2071
|
cap *= 2;
|
|
2068
2072
|
char *grown = realloc(buf, cap);
|
|
2069
2073
|
if (!grown) {
|
|
2070
|
-
|
|
2071
|
-
abort();
|
|
2074
|
+
scr_trap("scriptc: out of memory\n");
|
|
2072
2075
|
}
|
|
2073
2076
|
buf = grown;
|
|
2074
2077
|
}
|
|
@@ -2276,8 +2279,7 @@ double scr_stats_mtime_ms(ScrStats *s) { return s->mtime_ms; }
|
|
|
2276
2279
|
static ScrStats *scr_stats_of(const struct stat *st) {
|
|
2277
2280
|
ScrStats *s = malloc(sizeof(ScrStats));
|
|
2278
2281
|
if (!s) {
|
|
2279
|
-
|
|
2280
|
-
abort();
|
|
2282
|
+
scr_trap("scriptc: out of memory\n");
|
|
2281
2283
|
}
|
|
2282
2284
|
s->rc = 1;
|
|
2283
2285
|
s->is_file = S_ISREG(st->st_mode);
|
|
@@ -2374,16 +2376,14 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
|
|
|
2374
2376
|
}
|
|
2375
2377
|
ScrScandir *s = malloc(sizeof *s);
|
|
2376
2378
|
if (!s) {
|
|
2377
|
-
|
|
2378
|
-
abort();
|
|
2379
|
+
scr_trap("scriptc: out of memory\n");
|
|
2379
2380
|
}
|
|
2380
2381
|
s->len = 0;
|
|
2381
2382
|
s->cap = 8;
|
|
2382
2383
|
s->names = malloc(s->cap * sizeof *s->names);
|
|
2383
2384
|
s->kinds = malloc(s->cap);
|
|
2384
2385
|
if (!s->names || !s->kinds) {
|
|
2385
|
-
|
|
2386
|
-
abort();
|
|
2386
|
+
scr_trap("scriptc: out of memory\n");
|
|
2387
2387
|
}
|
|
2388
2388
|
const struct dirent *ent;
|
|
2389
2389
|
while ((ent = readdir(d)) != NULL) {
|
|
@@ -2424,8 +2424,7 @@ ScrScandir *scr_fs_scandir(ScrStr *path) {
|
|
|
2424
2424
|
s->names = realloc(s->names, s->cap * sizeof *s->names);
|
|
2425
2425
|
s->kinds = realloc(s->kinds, s->cap);
|
|
2426
2426
|
if (!s->names || !s->kinds) {
|
|
2427
|
-
|
|
2428
|
-
abort();
|
|
2427
|
+
scr_trap("scriptc: out of memory\n");
|
|
2429
2428
|
}
|
|
2430
2429
|
}
|
|
2431
2430
|
s->names[s->len] = scr_str_new(ent->d_name, strlen(ent->d_name));
|
|
@@ -2535,8 +2534,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2535
2534
|
size_t size = (size_t)n;
|
|
2536
2535
|
unsigned char *bytes = malloc(size ? size : 1);
|
|
2537
2536
|
if (!bytes) {
|
|
2538
|
-
|
|
2539
|
-
abort();
|
|
2537
|
+
scr_trap("scriptc: out of memory\n");
|
|
2540
2538
|
}
|
|
2541
2539
|
arc4random_buf(bytes, size);
|
|
2542
2540
|
ScrStr *out;
|
|
@@ -2544,8 +2542,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2544
2542
|
static const char hex[] = "0123456789abcdef";
|
|
2545
2543
|
char *buf = malloc(size * 2 + 1);
|
|
2546
2544
|
if (!buf) {
|
|
2547
|
-
|
|
2548
|
-
abort();
|
|
2545
|
+
scr_trap("scriptc: out of memory\n");
|
|
2549
2546
|
}
|
|
2550
2547
|
for (size_t i = 0; i < size; i++) {
|
|
2551
2548
|
buf[i * 2] = hex[bytes[i] >> 4];
|
|
@@ -2559,8 +2556,7 @@ ScrStr *scr_crypto_random_string(double n, ScrStr *enc) {
|
|
|
2559
2556
|
size_t outlen = (size + 2) / 3 * 4;
|
|
2560
2557
|
char *buf = malloc(outlen + 1);
|
|
2561
2558
|
if (!buf) {
|
|
2562
|
-
|
|
2563
|
-
abort();
|
|
2559
|
+
scr_trap("scriptc: out of memory\n");
|
|
2564
2560
|
}
|
|
2565
2561
|
size_t o = 0;
|
|
2566
2562
|
for (size_t i = 0; i < size; i += 3) {
|
|
@@ -2899,8 +2895,7 @@ static bool scr_x509_der(const uint8_t *in, size_t n, const uint8_t **der, size_
|
|
|
2899
2895
|
}
|
|
2900
2896
|
uint8_t *out = malloc(((size_t)(stop - b) / 4 + 1) * 3 + 3);
|
|
2901
2897
|
if (!out) {
|
|
2902
|
-
|
|
2903
|
-
abort();
|
|
2898
|
+
scr_trap("scriptc: out of memory\n");
|
|
2904
2899
|
}
|
|
2905
2900
|
size_t o = 0;
|
|
2906
2901
|
unsigned acc = 0;
|
|
@@ -3116,8 +3111,7 @@ static uint32_t scr_to_uint32(double d);
|
|
|
3116
3111
|
static ScrStr *scr_str_from_units(size_t n, uint32_t (*unit)(void *, size_t), void *src) {
|
|
3117
3112
|
char *out = malloc(n * 3 + 1); /* worst case: 3 bytes per UTF-16 unit */
|
|
3118
3113
|
if (!out) {
|
|
3119
|
-
|
|
3120
|
-
abort();
|
|
3114
|
+
scr_trap("scriptc: out of memory\n");
|
|
3121
3115
|
}
|
|
3122
3116
|
size_t o = 0;
|
|
3123
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]);
|