@scriptc/cli-darwin-x64 0.2.3 → 0.2.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/dist/THIRD_PARTY_NOTICES +1 -1
- package/dist/bin/scriptc +0 -0
- package/dist/bin/scriptc.json +1 -1
- package/dist/lib/declarations/scriptc-node-fallback.d.ts +915 -215
- package/dist/lib/declarations/scriptc-overrides.d.ts +5 -1
- package/dist/lib/declarations/scriptc.d.ts +22 -2
- package/dist/lib/llvm/bin/scriptc-llvm-codegen +0 -0
- package/dist/lib/llvm/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-dev/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/library-thread-release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/default/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_array.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bigint.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_bytes_io.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_copying.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_cycle.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_json.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_lib.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_map.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_number.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_regex.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_string.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic/scr_util_compare.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/dynamic-text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/artifacts/release/runtime/text-decoder-legacy/scr_bytes.o +0 -0
- package/dist/lib/runtime-darwin-x64/package.json +1 -1
- package/dist/lib/runtime-darwin-x64/runtime-pack.json +215 -215
- package/dist/lib/runtime-sources/package.json +1 -1
- package/dist/lib/runtime-sources/src/scr_array.c +317 -40
- package/dist/lib/runtime-sources/src/scr_async.test.ts +16 -6
- package/dist/lib/runtime-sources/src/scr_bigint.c +15 -0
- package/dist/lib/runtime-sources/src/scr_bytes.c +437 -216
- package/dist/lib/runtime-sources/src/scr_bytes.test.c +85 -0
- package/dist/lib/runtime-sources/src/scr_bytes_io.c +0 -34
- package/dist/lib/runtime-sources/src/scr_copying.c +12 -2
- package/dist/lib/runtime-sources/src/scr_cycle.c +84 -60
- package/dist/lib/runtime-sources/src/scr_json.c +494 -161
- package/dist/lib/runtime-sources/src/scr_json.test.c +323 -1
- package/dist/lib/runtime-sources/src/scr_json.test.ts +58 -25
- package/dist/lib/runtime-sources/src/scr_key.h +68 -0
- package/dist/lib/runtime-sources/src/scr_lib.c +177 -89
- package/dist/lib/runtime-sources/src/scr_map.c +268 -96
- package/dist/lib/runtime-sources/src/scr_number.c +2 -4
- package/dist/lib/runtime-sources/src/scr_numeric.h +25 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.c +37 -0
- package/dist/lib/runtime-sources/src/scr_numeric.test.ts +33 -0
- package/dist/lib/runtime-sources/src/scr_regex.c +255 -145
- package/dist/lib/runtime-sources/src/scr_runtime.h +76 -19
- package/dist/lib/runtime-sources/src/scr_string.c +184 -42
- package/package.json +1 -1
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
#include "scr_runtime.h"
|
|
2
2
|
#include <assert.h>
|
|
3
|
+
#include <math.h>
|
|
3
4
|
#include <stdio.h>
|
|
5
|
+
#include <string.h>
|
|
6
|
+
|
|
7
|
+
#ifdef SCR_RC_AUDIT
|
|
8
|
+
long scr_str_live_count(void);
|
|
9
|
+
long scr_dyn_key_live_count(void);
|
|
10
|
+
#endif
|
|
4
11
|
|
|
5
12
|
static void put(ScrDyn *map, ScrDyn *key, ScrDyn *value) {
|
|
6
13
|
ScrDyn *args[] = {key, value};
|
|
@@ -20,8 +27,323 @@ static ScrDyn *nothing(ScrClosure *closure, ScrDyn *const *args, size_t argc) {
|
|
|
20
27
|
return scr_dyn_retain(scr_dyn_undefined());
|
|
21
28
|
}
|
|
22
29
|
|
|
30
|
+
static void json_string_boundaries(void) {
|
|
31
|
+
/* Every escape/control at every word alignment, followed by raw UTF-8.
|
|
32
|
+
* ASan also checks short tails that cannot supply a complete word. */
|
|
33
|
+
const char suffix[] = "tail\xF0\x9F\x99\x82\xE9\x9B\xAA";
|
|
34
|
+
for (size_t prefix = 0; prefix < 64; prefix++) {
|
|
35
|
+
for (unsigned special = 0; special < 34; special++) {
|
|
36
|
+
char bytes[96];
|
|
37
|
+
memset(bytes, 'a', prefix);
|
|
38
|
+
bytes[prefix] = special < 32 ? (char)special : special == 32 ? '"' : '\\';
|
|
39
|
+
memcpy(bytes + prefix + 1, suffix, sizeof suffix - 1);
|
|
40
|
+
size_t length = prefix + sizeof suffix;
|
|
41
|
+
ScrStr *original = scr_str_new(bytes, length);
|
|
42
|
+
ScrJsonBuf buffer;
|
|
43
|
+
scr_jb_init(&buffer);
|
|
44
|
+
scr_jb_put_json_str(&buffer, original);
|
|
45
|
+
ScrStr *encoded = scr_jb_finish(&buffer);
|
|
46
|
+
ScrDyn *parsed = scr_json_parse(encoded);
|
|
47
|
+
assert(parsed && parsed->kind == SCR_DYN_STR && !scr_exc_pending());
|
|
48
|
+
assert(scr_str_eq(original, parsed->v.str));
|
|
49
|
+
scr_dyn_release(parsed);
|
|
50
|
+
scr_str_release(encoded);
|
|
51
|
+
scr_str_release(original);
|
|
52
|
+
|
|
53
|
+
if (special < 32) {
|
|
54
|
+
char invalid[68];
|
|
55
|
+
invalid[0] = '"';
|
|
56
|
+
memset(invalid + 1, 'a', prefix);
|
|
57
|
+
invalid[prefix + 1] = (char)special;
|
|
58
|
+
invalid[prefix + 2] = '"';
|
|
59
|
+
ScrStr *input = scr_str_new(invalid, prefix + 3);
|
|
60
|
+
assert(!scr_json_parse(input) && scr_exc_pending());
|
|
61
|
+
scr_exc_clear();
|
|
62
|
+
scr_str_release(input);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
char plain[68];
|
|
66
|
+
plain[0] = '"';
|
|
67
|
+
memset(plain + 1, 'z', prefix);
|
|
68
|
+
plain[prefix + 1] = '"';
|
|
69
|
+
ScrStr *input = scr_str_new(plain, prefix + 2);
|
|
70
|
+
ScrDyn *parsed = scr_json_parse(input);
|
|
71
|
+
assert(parsed && parsed->v.str->len == prefix && !scr_exc_pending());
|
|
72
|
+
scr_dyn_release(parsed);
|
|
73
|
+
scr_str_release(input);
|
|
74
|
+
input = scr_str_new(plain, prefix + 1);
|
|
75
|
+
assert(!scr_json_parse(input) && scr_exc_pending());
|
|
76
|
+
scr_exc_clear();
|
|
77
|
+
scr_str_release(input);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
static void checked_storage(void) {
|
|
82
|
+
/* Reuse after deletion, changing field order, embedded NUL and escaped
|
|
83
|
+
* duplicate names must leave independently owned keys and values. */
|
|
84
|
+
for (int round = 0; round < 100; round++) {
|
|
85
|
+
const char *text = round % 2 ? "{\"alpha\":1,\"beta\":2,\"gamma\":3}"
|
|
86
|
+
: "{\"gamma\":3,\"alpha\":0,\"\\u0061lpha\":1,\"beta\":2}";
|
|
87
|
+
ScrStr *input = scr_str_new(text, strlen(text));
|
|
88
|
+
ScrDyn *object = scr_json_parse(input);
|
|
89
|
+
scr_str_release(input);
|
|
90
|
+
assert(object && object->v.obj.len == 3);
|
|
91
|
+
assert(scr_dyn_obj_get(object, "alpha", 5)->v.num == 1);
|
|
92
|
+
ScrStr *key = scr_str_new("beta", 4);
|
|
93
|
+
scr_dyn_key_delete(object, key, true);
|
|
94
|
+
scr_str_release(key);
|
|
95
|
+
assert(!scr_dyn_obj_get(object, "beta", 4));
|
|
96
|
+
assert(scr_dyn_obj_get(object, "gamma", 5)->v.num == 3);
|
|
97
|
+
char mutable_key[] = "new\0key";
|
|
98
|
+
scr_dyn_obj_set(object, mutable_key, sizeof mutable_key - 1, scr_dyn_new_num(4));
|
|
99
|
+
mutable_key[0] = 'x';
|
|
100
|
+
assert(scr_dyn_obj_get(object, "new\0key", 7)->v.num == 4);
|
|
101
|
+
scr_dyn_release(object);
|
|
102
|
+
}
|
|
103
|
+
/* Larger objects and long names leave no stale pooled tail keys when a
|
|
104
|
+
* later small object grows through the same capacity. */
|
|
105
|
+
for (int round = 0; round < 4; round++) {
|
|
106
|
+
ScrDyn *object = scr_dyn_new_obj();
|
|
107
|
+
for (int i = 0; i < 80; i++) {
|
|
108
|
+
char key[160];
|
|
109
|
+
memset(key, 'a' + i % 20, sizeof key);
|
|
110
|
+
int prefix = snprintf(key, sizeof key, "%d:", i);
|
|
111
|
+
memset(key + prefix, 'a' + i % 20, sizeof key - (size_t)prefix);
|
|
112
|
+
scr_dyn_obj_set(object, key, sizeof key, scr_dyn_new_num(i));
|
|
113
|
+
assert(scr_dyn_obj_get(object, key, sizeof key)->v.num == i);
|
|
114
|
+
}
|
|
115
|
+
scr_dyn_release(object);
|
|
116
|
+
}
|
|
117
|
+
/* Cross index growth boundaries, invalidate moved entry positions, then
|
|
118
|
+
* recreate the index from survivors. Repeat after pool reuse. */
|
|
119
|
+
for (int round = 0; round < 4; round++) {
|
|
120
|
+
ScrDyn *object = scr_dyn_new_obj();
|
|
121
|
+
assert(!object->v.obj.index);
|
|
122
|
+
for (int i = 0; i < 129; i++) {
|
|
123
|
+
char key[16];
|
|
124
|
+
int length = snprintf(key, sizeof key, "key-%d", i);
|
|
125
|
+
scr_dyn_obj_set(object, key, (size_t)length, scr_dyn_new_num(i));
|
|
126
|
+
assert((object->v.obj.index != NULL) == (i >= 31));
|
|
127
|
+
}
|
|
128
|
+
for (int i = 0; i < 129; i++) {
|
|
129
|
+
char key[16];
|
|
130
|
+
int length = snprintf(key, sizeof key, "key-%d", i);
|
|
131
|
+
assert(scr_dyn_obj_get(object, key, (size_t)length)->v.num == i);
|
|
132
|
+
if (i % 3 == 0) {
|
|
133
|
+
ScrStr *name = scr_str_new(key, (size_t)length);
|
|
134
|
+
scr_dyn_key_delete(object, name, true);
|
|
135
|
+
scr_str_release(name);
|
|
136
|
+
assert(!scr_dyn_obj_get(object, key, (size_t)length));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
scr_dyn_obj_set(object, "last", 4, scr_dyn_new_num(129));
|
|
140
|
+
assert(object->v.obj.index);
|
|
141
|
+
for (int i = 0; i < 129; i++) {
|
|
142
|
+
char key[16];
|
|
143
|
+
int length = snprintf(key, sizeof key, "key-%d", i);
|
|
144
|
+
ScrDyn *value = scr_dyn_obj_get(object, key, (size_t)length);
|
|
145
|
+
assert(i % 3 == 0 ? value == NULL : value && value->v.num == i);
|
|
146
|
+
}
|
|
147
|
+
scr_dyn_obj_set(object, "key-128", 7, scr_dyn_new_num(900));
|
|
148
|
+
assert(object->v.obj.len == 87);
|
|
149
|
+
assert(scr_dyn_obj_get(object, "key-128", 7)->v.num == 900);
|
|
150
|
+
scr_dyn_release(object);
|
|
151
|
+
}
|
|
152
|
+
/* A direct step is authorized only by the captured builtin method. */
|
|
153
|
+
ScrDyn *source = scr_dyn_new_arr();
|
|
154
|
+
scr_dyn_arr_push(source, scr_dyn_new_num(7));
|
|
155
|
+
scr_dyn_arr_push(source, scr_dyn_retain(scr_dyn_undefined()));
|
|
156
|
+
ScrStr *spell = scr_str_new("source", 6);
|
|
157
|
+
ScrDyn *iterator = scr_dyn_iterator(source, spell);
|
|
158
|
+
scr_str_release(spell);
|
|
159
|
+
ScrDyn *next = scr_dyn_handle_ops_of(iterator)->get(iterator->v.handle.ptr, "next", 4);
|
|
160
|
+
assert(scr_dyn_iterator_can_step(iterator, next));
|
|
161
|
+
assert(!scr_dyn_iterator_can_step(source, next));
|
|
162
|
+
assert(!scr_dyn_iterator_can_step(iterator, scr_dyn_undefined()));
|
|
163
|
+
ScrDyn *item = scr_dyn_iterator_step(iterator);
|
|
164
|
+
assert(item->v.num == 7 && !scr_dyn_iterator_step_done(iterator));
|
|
165
|
+
scr_dyn_release(item);
|
|
166
|
+
item = scr_dyn_iterator_step(iterator);
|
|
167
|
+
assert(item->kind == SCR_DYN_UNDEF && !scr_dyn_iterator_step_done(iterator));
|
|
168
|
+
scr_dyn_release(item);
|
|
169
|
+
scr_dyn_arr_push(source, scr_dyn_new_num(9));
|
|
170
|
+
item = scr_dyn_iterator_step(iterator);
|
|
171
|
+
assert(item->v.num == 9 && !scr_dyn_iterator_step_done(iterator));
|
|
172
|
+
scr_dyn_release(item);
|
|
173
|
+
item = scr_dyn_iterator_step(iterator);
|
|
174
|
+
assert(item->kind == SCR_DYN_UNDEF && scr_dyn_iterator_step_done(iterator));
|
|
175
|
+
scr_dyn_release(item);
|
|
176
|
+
scr_dyn_arr_push(source, scr_dyn_new_num(11));
|
|
177
|
+
item = scr_dyn_iterator_step(iterator);
|
|
178
|
+
assert(item->kind == SCR_DYN_UNDEF && scr_dyn_iterator_step_done(iterator));
|
|
179
|
+
scr_dyn_release(item);
|
|
180
|
+
scr_dyn_release(next);
|
|
181
|
+
scr_dyn_release(iterator);
|
|
182
|
+
scr_dyn_release(source);
|
|
183
|
+
assert(!scr_exc_pending());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static void shared_property_keys(void) {
|
|
187
|
+
#ifdef SCR_RC_AUDIT
|
|
188
|
+
long before = scr_dyn_key_live_count();
|
|
189
|
+
#endif
|
|
190
|
+
/* Distinct objects share bytes, not values or property attributes. Key
|
|
191
|
+
* deletion, a collected owner and a caller-owned input cannot invalidate
|
|
192
|
+
* the surviving entry. */
|
|
193
|
+
ScrDyn *first = scr_dyn_new_obj(), *second = scr_dyn_new_obj();
|
|
194
|
+
char key[] = "shared\0name";
|
|
195
|
+
scr_dyn_obj_set(first, key, sizeof key - 1, scr_dyn_new_num(1));
|
|
196
|
+
scr_dyn_obj_set(second, key, sizeof key - 1, scr_dyn_new_num(2));
|
|
197
|
+
assert(first->v.obj.entries[0].key == second->v.obj.entries[0].key);
|
|
198
|
+
key[0] = 'x';
|
|
199
|
+
ScrStr *name = scr_str_new("shared\0name", sizeof key - 1);
|
|
200
|
+
scr_dyn_key_delete(first, name, true);
|
|
201
|
+
scr_str_release(name);
|
|
202
|
+
assert(scr_dyn_obj_get(second, "shared\0name", sizeof key - 1)->v.num == 2);
|
|
203
|
+
scr_dyn_obj_set(first, "shared\0name", sizeof key - 1, scr_dyn_new_num(3));
|
|
204
|
+
scr_dyn_obj_set(first, "self", 4, scr_dyn_retain(first));
|
|
205
|
+
scr_dyn_release(first);
|
|
206
|
+
scr_collect_cycles();
|
|
207
|
+
assert(scr_dyn_obj_get(second, "shared\0name", sizeof key - 1)->v.num == 2);
|
|
208
|
+
scr_dyn_release(second);
|
|
209
|
+
|
|
210
|
+
/* More distinct live names than weak slots force collisions. Releasing
|
|
211
|
+
* an evicted owner must not clear or free the replacement's storage. */
|
|
212
|
+
ScrDyn *objects[600];
|
|
213
|
+
for (int round = 0; round < 2; round++) {
|
|
214
|
+
for (int i = 0; i < 600; i++) {
|
|
215
|
+
char bytes[32];
|
|
216
|
+
int length = snprintf(bytes, sizeof bytes, "field-%d", i);
|
|
217
|
+
objects[i] = scr_dyn_new_obj();
|
|
218
|
+
scr_dyn_obj_set(objects[i], bytes, (size_t)length, scr_dyn_new_num(i));
|
|
219
|
+
}
|
|
220
|
+
for (int i = 0; i < 600; i++) {
|
|
221
|
+
char bytes[32];
|
|
222
|
+
int length = snprintf(bytes, sizeof bytes, "field-%d", i);
|
|
223
|
+
assert(scr_dyn_obj_get(objects[i], bytes, (size_t)length)->v.num == i);
|
|
224
|
+
scr_dyn_release(objects[i]);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
#ifdef SCR_RC_AUDIT
|
|
228
|
+
assert(scr_dyn_key_live_count() == before);
|
|
229
|
+
#endif
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static void checked_leaf_cycles(void) {
|
|
233
|
+
/* Object properties omit primitives from trial deletion, while arrays and
|
|
234
|
+
* captured unknown values still trace them. Exercise shared leaves through
|
|
235
|
+
* both edge kinds, with and without an external owner, in either generation. */
|
|
236
|
+
for (int old = 0; old < 2; old++) {
|
|
237
|
+
for (int external = 0; external < 2; external++) {
|
|
238
|
+
#ifdef SCR_RC_AUDIT
|
|
239
|
+
long before_dyns = scr_dyn_live_count();
|
|
240
|
+
long before_strings = scr_str_live_count();
|
|
241
|
+
#endif
|
|
242
|
+
ScrStr *text = scr_str_new("survives either edge", 20);
|
|
243
|
+
ScrDyn *leaf = scr_dyn_new_str(text);
|
|
244
|
+
scr_str_release(text);
|
|
245
|
+
if (old) scr_cyc_hdr(leaf)->gen = SCR_CYC_MATURE;
|
|
246
|
+
ScrDyn *first = scr_dyn_new_obj(), *second = scr_dyn_new_obj();
|
|
247
|
+
ScrDyn *array = scr_dyn_new_arr();
|
|
248
|
+
ScrClosure *closure = scr_closure_new(NULL, 1);
|
|
249
|
+
closure->caps[0] = scr_box_new_obj(scr_dyn_retain_v, scr_dyn_release_v, scr_dyn_trace_v);
|
|
250
|
+
scr_box_set_ref(closure->caps[0], scr_dyn_retain(leaf));
|
|
251
|
+
scr_dyn_obj_set(first, "callback", 8, scr_dyn_new_func(closure, nothing, 0, "func()=>dyn", "leaf"));
|
|
252
|
+
scr_dyn_obj_set(first, "leaf", 4, scr_dyn_retain(leaf));
|
|
253
|
+
scr_dyn_obj_set(second, "leaf", 4, scr_dyn_retain(leaf));
|
|
254
|
+
scr_dyn_obj_set(second, "number", 6, scr_dyn_new_num(42));
|
|
255
|
+
scr_dyn_obj_set(second, "empty", 5, scr_dyn_new_null());
|
|
256
|
+
scr_dyn_obj_set(second, "missing", 7, scr_dyn_retain(scr_dyn_undefined()));
|
|
257
|
+
scr_dyn_arr_push(array, scr_dyn_retain(leaf));
|
|
258
|
+
scr_dyn_arr_push(array, scr_dyn_retain(first));
|
|
259
|
+
scr_dyn_obj_set(first, "next", 4, scr_dyn_retain(second));
|
|
260
|
+
scr_dyn_obj_set(second, "back", 4, scr_dyn_retain(first));
|
|
261
|
+
scr_dyn_obj_set(second, "array", 5, array);
|
|
262
|
+
if (!external) scr_dyn_release(leaf);
|
|
263
|
+
scr_dyn_release(first);
|
|
264
|
+
scr_dyn_release(second);
|
|
265
|
+
scr_cyc_collect_scheduled();
|
|
266
|
+
scr_collect_cycles();
|
|
267
|
+
if (external) {
|
|
268
|
+
assert(leaf->rc == 1 && leaf->v.str->len == 20);
|
|
269
|
+
scr_dyn_release(leaf);
|
|
270
|
+
}
|
|
271
|
+
#ifdef SCR_RC_AUDIT
|
|
272
|
+
assert(scr_dyn_live_count() == before_dyns);
|
|
273
|
+
assert(scr_str_live_count() == before_strings);
|
|
274
|
+
#endif
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* A previous trace snapshot must not survive a property mutation: the
|
|
279
|
+
* next collection must trace a new object edge or release a new leaf. */
|
|
280
|
+
for (int leaf_after = 0; leaf_after < 2; leaf_after++) {
|
|
281
|
+
#ifdef SCR_RC_AUDIT
|
|
282
|
+
long before = scr_dyn_live_count();
|
|
283
|
+
#endif
|
|
284
|
+
ScrDyn *object = scr_dyn_new_obj(), *child = scr_dyn_new_obj();
|
|
285
|
+
scr_dyn_obj_set(object, "self", 4, scr_dyn_retain(object));
|
|
286
|
+
scr_dyn_obj_set(object, "value", 5, leaf_after ? scr_dyn_retain(child) : scr_dyn_new_num(1));
|
|
287
|
+
scr_dyn_release(scr_dyn_retain(object));
|
|
288
|
+
scr_collect_cycles();
|
|
289
|
+
scr_dyn_obj_set(object, "value", 5, leaf_after ? scr_dyn_new_num(2) : scr_dyn_retain(child));
|
|
290
|
+
scr_dyn_obj_set(child, "parent", 6, scr_dyn_retain(object));
|
|
291
|
+
scr_dyn_release(child);
|
|
292
|
+
scr_dyn_release(object);
|
|
293
|
+
scr_collect_cycles();
|
|
294
|
+
#ifdef SCR_RC_AUDIT
|
|
295
|
+
assert(scr_dyn_live_count() == before);
|
|
296
|
+
#endif
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static void checked_number_storage(void) {
|
|
301
|
+
#ifdef SCR_RC_AUDIT
|
|
302
|
+
long before = scr_dyn_live_count();
|
|
303
|
+
#endif
|
|
304
|
+
for (int value = -130; value < 258; value++) {
|
|
305
|
+
ScrDyn *first = scr_dyn_new_num(value), *second = scr_dyn_new_num(value);
|
|
306
|
+
assert(first->kind == SCR_DYN_NUM && first->v.num == value);
|
|
307
|
+
assert(scr_dyn_strict_eq(first, second));
|
|
308
|
+
if (value >= -128 && value <= 255) assert(first == second && first->rc == SIZE_MAX);
|
|
309
|
+
ScrDyn *array = scr_dyn_new_arr();
|
|
310
|
+
scr_dyn_arr_push(array, first);
|
|
311
|
+
scr_dyn_arr_push(array, second);
|
|
312
|
+
scr_dyn_arr_push(array, scr_dyn_retain(array));
|
|
313
|
+
scr_dyn_release(array);
|
|
314
|
+
scr_collect_cycles();
|
|
315
|
+
}
|
|
316
|
+
const double special[] = {-0.0, 0.5, -0.5, NAN, INFINITY, -INFINITY, 9007199254740991.0};
|
|
317
|
+
for (size_t i = 0; i < sizeof special / sizeof special[0]; i++) {
|
|
318
|
+
ScrDyn *value = scr_dyn_new_num(special[i]);
|
|
319
|
+
assert(value->rc != SIZE_MAX);
|
|
320
|
+
assert(isnan(special[i]) ? isnan(value->v.num) : value->v.num == special[i]);
|
|
321
|
+
if (special[i] == 0) assert(signbit(value->v.num));
|
|
322
|
+
scr_dyn_release(value);
|
|
323
|
+
}
|
|
324
|
+
const char raw[] = "[-0,0,1.0,1e2,-128,255,256,1e400]";
|
|
325
|
+
ScrStr *input = scr_str_new(raw, sizeof raw - 1);
|
|
326
|
+
ScrDyn *parsed = scr_json_parse(input);
|
|
327
|
+
assert(parsed && parsed->v.arr.len == 8);
|
|
328
|
+
assert(signbit(parsed->v.arr.items[0]->v.num));
|
|
329
|
+
assert(!signbit(parsed->v.arr.items[1]->v.num));
|
|
330
|
+
assert(parsed->v.arr.items[2] == scr_dyn_new_num(1));
|
|
331
|
+
assert(parsed->v.arr.items[3] == scr_dyn_new_num(100));
|
|
332
|
+
assert(isinf(parsed->v.arr.items[7]->v.num));
|
|
333
|
+
scr_dyn_release(parsed);
|
|
334
|
+
scr_str_release(input);
|
|
335
|
+
#ifdef SCR_RC_AUDIT
|
|
336
|
+
assert(scr_dyn_live_count() == before);
|
|
337
|
+
#endif
|
|
338
|
+
}
|
|
339
|
+
|
|
23
340
|
int main(void) {
|
|
341
|
+
json_string_boundaries();
|
|
24
342
|
scr_init();
|
|
343
|
+
checked_storage();
|
|
344
|
+
shared_property_keys();
|
|
345
|
+
checked_leaf_cycles();
|
|
346
|
+
checked_number_storage();
|
|
25
347
|
/* Native Set boxes may own headerless scalar/string maps. Collecting an
|
|
26
348
|
* enclosing cycle must neither trace those leaves nor skip their release. */
|
|
27
349
|
for (int i = 0; i < 2000; i++) {
|
|
@@ -177,6 +499,6 @@ int main(void) {
|
|
|
177
499
|
scr_dyn_release(key);
|
|
178
500
|
scr_dyn_release(first);
|
|
179
501
|
assert(!scr_exc_pending());
|
|
180
|
-
puts("weak metadata lifetime checks passed");
|
|
502
|
+
puts("checked storage and weak metadata lifetime checks passed");
|
|
181
503
|
return 0;
|
|
182
504
|
}
|
|
@@ -7,28 +7,61 @@ import { expect, test } from "vitest";
|
|
|
7
7
|
|
|
8
8
|
const exec = promisify(execFile);
|
|
9
9
|
|
|
10
|
-
test.each([false, true])(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
10
|
+
test.each([false, true])(
|
|
11
|
+
"checked storage and weak metadata preserve ownership (audit=%s)",
|
|
12
|
+
async (audit) => {
|
|
13
|
+
const scratch = await mkdtemp(join(tmpdir(), "scriptc-weak-map-"));
|
|
14
|
+
const src = import.meta.dirname;
|
|
15
|
+
const binary = join(scratch, "weak-map");
|
|
16
|
+
try {
|
|
17
|
+
await exec("clang", [
|
|
18
|
+
"-std=c11",
|
|
19
|
+
"-O1",
|
|
20
|
+
"-Wall",
|
|
21
|
+
"-Wextra",
|
|
22
|
+
"-fsanitize=address,undefined",
|
|
23
|
+
...(audit ? ["-DSCR_RC_AUDIT"] : []),
|
|
24
|
+
"-I",
|
|
25
|
+
src,
|
|
26
|
+
"-o",
|
|
27
|
+
binary,
|
|
28
|
+
...[
|
|
29
|
+
"scr_json.test.c",
|
|
30
|
+
"scr_json.c",
|
|
31
|
+
"scr_string.c",
|
|
32
|
+
"scr_array.c",
|
|
33
|
+
"scr_map.c",
|
|
34
|
+
"scr_exception.c",
|
|
35
|
+
"scr_error.c",
|
|
36
|
+
"scr_number.c",
|
|
37
|
+
"scr_console.c",
|
|
38
|
+
"scr_closure.c",
|
|
39
|
+
"scr_object.c",
|
|
40
|
+
"scr_union.c",
|
|
41
|
+
"scr_cycle.c",
|
|
42
|
+
"scr_lib.c",
|
|
43
|
+
"scr_bytes.c",
|
|
44
|
+
"scr_bigint.c",
|
|
45
|
+
"scr_url.c",
|
|
46
|
+
"scr_url_params.c",
|
|
47
|
+
"scr_path.c",
|
|
48
|
+
].map((file) => join(src, file)),
|
|
49
|
+
...(process.platform === "linux" ? ["-D_GNU_SOURCE", "-lm"] : []),
|
|
50
|
+
]);
|
|
51
|
+
for (const threshold of ["1", "7", "256"]) {
|
|
52
|
+
const result = await exec(binary, [], {
|
|
53
|
+
env: {
|
|
54
|
+
...process.env,
|
|
55
|
+
SCR_CYCLE_THRESHOLD: threshold,
|
|
56
|
+
ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1",
|
|
57
|
+
UBSAN_OPTIONS: "halt_on_error=1",
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
expect(result.stdout).toBe("checked storage and weak metadata lifetime checks passed\n");
|
|
61
|
+
expect(result.stderr).toBe("");
|
|
62
|
+
}
|
|
63
|
+
} finally {
|
|
64
|
+
await rm(scratch, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/* Internal key hashing and canonical array-index ordering shared by native
|
|
2
|
+
* maps and checked objects. Hashes never escape into JavaScript values. */
|
|
3
|
+
#ifndef SCR_KEY_H
|
|
4
|
+
#define SCR_KEY_H
|
|
5
|
+
#include <stdbool.h>
|
|
6
|
+
#include <stddef.h>
|
|
7
|
+
#include <stdint.h>
|
|
8
|
+
#include <stdlib.h>
|
|
9
|
+
#include <string.h>
|
|
10
|
+
|
|
11
|
+
static inline uint64_t scr_key_mix(uint64_t value) {
|
|
12
|
+
value ^= value >> 30;
|
|
13
|
+
value *= UINT64_C(0xbf58476d1ce4e5b9);
|
|
14
|
+
value ^= value >> 27;
|
|
15
|
+
value *= UINT64_C(0x94d049bb133111eb);
|
|
16
|
+
return value ^ (value >> 31);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/* Unaligned loads stay inside the input. Hashing is process-local, so host
|
|
20
|
+
* byte order is immaterial; equal byte strings always follow the same path. */
|
|
21
|
+
static inline uint64_t scr_key_hash(const char *bytes, size_t length) {
|
|
22
|
+
uint64_t hash = UINT64_C(0x9e3779b97f4a7c15) ^ length;
|
|
23
|
+
size_t i = 0;
|
|
24
|
+
while (length - i >= sizeof(uint64_t)) {
|
|
25
|
+
uint64_t word;
|
|
26
|
+
memcpy(&word, bytes + i, sizeof word);
|
|
27
|
+
hash = scr_key_mix(hash ^ word);
|
|
28
|
+
i += sizeof word;
|
|
29
|
+
}
|
|
30
|
+
uint64_t tail = 0;
|
|
31
|
+
if (i < length) memcpy(&tail, bytes + i, length - i);
|
|
32
|
+
return scr_key_mix(hash ^ tail);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static inline bool scr_key_array_index(const char *key, size_t length, uint32_t *out) {
|
|
36
|
+
if (length == 0 || length > 10 || (length > 1 && key[0] == '0')) return false;
|
|
37
|
+
uint64_t value = 0;
|
|
38
|
+
for (size_t i = 0; i < length; i++) {
|
|
39
|
+
if (key[i] < '0' || key[i] > '9') return false;
|
|
40
|
+
value = value * 10 + (unsigned)(key[i] - '0');
|
|
41
|
+
}
|
|
42
|
+
if (value >= UINT32_MAX) return false;
|
|
43
|
+
*out = (uint32_t)value;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
typedef struct {
|
|
48
|
+
uint32_t index;
|
|
49
|
+
size_t entry;
|
|
50
|
+
} ScrKeyIndex;
|
|
51
|
+
|
|
52
|
+
static inline int scr_key_index_compare(const void *left, const void *right) {
|
|
53
|
+
uint32_t a = ((const ScrKeyIndex *)left)->index;
|
|
54
|
+
uint32_t b = ((const ScrKeyIndex *)right)->index;
|
|
55
|
+
return (a > b) - (a < b);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Keys are unique. Already ordered inputs need no sort, while arbitrary
|
|
59
|
+
* numeric property insertion must not require quadratic enumeration. */
|
|
60
|
+
static inline void scr_key_index_sort(ScrKeyIndex *keys, size_t count) {
|
|
61
|
+
for (size_t i = 1; i < count; i++) {
|
|
62
|
+
if (keys[i - 1].index > keys[i].index) {
|
|
63
|
+
qsort(keys, count, sizeof *keys, scr_key_index_compare);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
#endif
|