yeptris 0.6.31.2-arm-linux-eabihf → 0.6.33.1-arm-linux-eabihf
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.
- checksums.yaml +4 -4
- data/lib/yeptris/3.4/native.so +0 -0
- data/lib/yeptris/node.rb +12 -3
- data/lib/yeptris/psych/visitors.rb +1 -1
- data/lib/yeptris/yaml.rb +1 -1
- data/lib/yeptris.rb +1 -1
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +17 -5
- data/vendor/libyeptris/src/yeptris/dom/dom.c +52 -2
- data/vendor/libyeptris/src/yeptris/dom/ytape.c +273 -18
- data/vendor/libyeptris/src/yeptris/emit/emit.c +22 -1
- data/vendor/libyeptris/src/yeptris/emit/style.c +13 -1
- data/vendor/libyeptris/src/yeptris/emit/writer.c +433 -50
- data/vendor/libyeptris/src/yeptris/emit/writer.h +7 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +83 -44
- data/vendor/libyeptris/src/yeptris/parse/engine.c +1189 -127
- data/vendor/libyeptris/src/yeptris/parse/engine.h +3 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +28 -3
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +12 -0
- data/vendor/libyeptris/src/yeptris/parse.c +12 -4
- data/vendor/libyeptris/src/yeptris/scan/scan.c +42 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +7 -0
- data/vendor/libyeptris/src/yeptris/tape.c +88 -1
- data/vendor/libyeptris/src/yeptris/tape_in.h +2 -0
- metadata +1 -1
|
@@ -36,6 +36,9 @@ int yep_engine_run(yep_engine* e, const char* buf, size_t len, const yep_sink* s
|
|
|
36
36
|
* from the stream's '&' occurrences (every anchor definition carries
|
|
37
37
|
* exactly one, so the count never undershoots). */
|
|
38
38
|
void yep_engine_prepare(yep_engine* e, const yep_text_stats* st);
|
|
39
|
+
/* the caller already BOM-sniffed/transcoded the bytes (parse.c,
|
|
40
|
+
* values.c): the engine must not re-strip a content U+FEFF */
|
|
41
|
+
void yep_engine_front_done(yep_engine* e);
|
|
39
42
|
|
|
40
43
|
/* Resumable stepping (TODO.impl/07): chunks accumulate; every feed
|
|
41
44
|
* parses the complete DOCUMENTS received so far (cut at `---` / `...`
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* strtod cross-checks. */
|
|
6
6
|
|
|
7
7
|
#include <errno.h>
|
|
8
|
+
#include <limits.h>
|
|
8
9
|
#include <math.h>
|
|
9
10
|
#include <stdlib.h>
|
|
10
11
|
#include <string.h>
|
|
@@ -160,9 +161,20 @@ int yep_num_i64(const char* p, uint32_t len, int64_t* out) {
|
|
|
160
161
|
}
|
|
161
162
|
long long v = 0;
|
|
162
163
|
while (*q >= '0' && *q <= '9') {
|
|
163
|
-
|
|
164
|
+
int d = *q - '0';
|
|
165
|
+
/* the ERANGE law, spelled out: the plain path rejects
|
|
166
|
+
* unrepresentable values via strtoll, so the fold must
|
|
167
|
+
* too (UBSan: 2222222222222222222 * 10 overflowed, the
|
|
168
|
+
* nightly's round on the combined build) */
|
|
169
|
+
if (v > (LLONG_MAX - (long long)d) / 10) {
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
172
|
+
v = v * 10 + d;
|
|
164
173
|
q++;
|
|
165
174
|
}
|
|
175
|
+
if (v > LLONG_MAX / 3600) {
|
|
176
|
+
return 1;
|
|
177
|
+
}
|
|
166
178
|
v *= 3600; /* e0 weight */
|
|
167
179
|
if (sign < 0)
|
|
168
180
|
v = -v;
|
|
@@ -172,14 +184,27 @@ int yep_num_i64(const char* p, uint32_t len, int64_t* out) {
|
|
|
172
184
|
long long g = 0;
|
|
173
185
|
int d = 0;
|
|
174
186
|
while (*q >= '0' && *q <= '9') {
|
|
175
|
-
|
|
187
|
+
int dg = *q - '0';
|
|
188
|
+
/* the group component rides the same ERANGE law as
|
|
189
|
+
* the first component -- the catch-124 fix guarded
|
|
190
|
+
* the hours loop but left this one raw (UBSan:
|
|
191
|
+
* 999999999999999999 * 10, the nightly's run
|
|
192
|
+
* 39049702014) */
|
|
193
|
+
if (g > (LLONG_MAX - (long long)dg) / 10) {
|
|
194
|
+
return 1;
|
|
195
|
+
}
|
|
196
|
+
g = g * 10 + dg;
|
|
176
197
|
q++;
|
|
177
198
|
d++;
|
|
178
199
|
}
|
|
179
200
|
if (d == 0) {
|
|
180
201
|
return 1;
|
|
181
202
|
}
|
|
182
|
-
|
|
203
|
+
long long w = groups == 0 ? 60 : 1; /* e1 then e2 */
|
|
204
|
+
if (g > LLONG_MAX / w || v > LLONG_MAX - g * w) {
|
|
205
|
+
return 1;
|
|
206
|
+
}
|
|
207
|
+
v += g * w;
|
|
183
208
|
groups++;
|
|
184
209
|
}
|
|
185
210
|
if (groups == 0 || *q != '\0') {
|
|
@@ -19,6 +19,18 @@
|
|
|
19
19
|
extern "C" {
|
|
20
20
|
#endif
|
|
21
21
|
|
|
22
|
+
/* libyaml's simple-key budget counts characters, not bytes: a
|
|
23
|
+
* multibyte code point costs one (the round-108 fuzz shrink carries a
|
|
24
|
+
* 2-byte char at byte delta 1025). Shared by the engine scanners, the
|
|
25
|
+
* DOM JSON builder, and the tape key checker. */
|
|
26
|
+
static inline int yep_simple_key_chars(const char* p, size_t n) {
|
|
27
|
+
int chars = 0;
|
|
28
|
+
for (size_t i = 0; i < n; i++) {
|
|
29
|
+
chars += ((((unsigned char)p[i]) & 0xC0) != 0x80);
|
|
30
|
+
}
|
|
31
|
+
return chars;
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
/* Finishes a double-quoted content span: escape sequences (\n \t \\ \" \x
|
|
23
35
|
* \u \U …), backslash-at-EOL continuation, and multi-line folding.
|
|
24
36
|
* Returns a pool-owned buffer of out_len bytes. */
|
|
@@ -156,10 +156,14 @@ YEPTRIS_API YeptrisDocument yeptris_parse_json(const char* buf, size_t len, Yept
|
|
|
156
156
|
st = YEPTRIS_ERROR_MEMORY;
|
|
157
157
|
goto jfail;
|
|
158
158
|
}
|
|
159
|
-
if (yep_tape_walk_lenient_fused(buf, len, off, t, 1, 1, 0) == YEPTRIS_OK
|
|
159
|
+
if (yep_tape_walk_lenient_fused(buf, len, off, t, 1, 1, 0) == YEPTRIS_OK &&
|
|
160
|
+
!yep_tape_long_simple_key(t)) {
|
|
160
161
|
/* strict_nums=1: the arms validated the numbers at
|
|
161
162
|
* record time — the settle pass is gone (the profile's
|
|
162
|
-
* 10% lane; the spans were cache-warm in the walk)
|
|
163
|
+
* 10% lane; the spans were cache-warm in the walk).
|
|
164
|
+
* The simple-key law: a >1024 flow key cannot
|
|
165
|
+
* re-serialize — the engine's clean error decides (run
|
|
166
|
+
* 38143486175) */
|
|
163
167
|
YeptrisDocument h = yep_json_doc_wrap(NULL, buf, len, sys, status);
|
|
164
168
|
if (h != NULL) {
|
|
165
169
|
((yeptris_document*)h)->lazy_tape = t;
|
|
@@ -366,8 +370,11 @@ engine_enter:
|
|
|
366
370
|
* entirely — no anchors exist (the profile's 4.4% memchr
|
|
367
371
|
* lane on the json corpora). */
|
|
368
372
|
yep_text_stats amp_only = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
369
|
-
|
|
370
|
-
|
|
373
|
+
/* (NULL, 0) passes the arg guard: NULL + 0 is UB, not an
|
|
374
|
+
* empty range (UBSan, the first nightly under the combined
|
|
375
|
+
* fuzz build) */
|
|
376
|
+
const char* q = data == NULL ? "" : data;
|
|
377
|
+
const char* end = q + data_len;
|
|
371
378
|
if (q != NULL) {
|
|
372
379
|
while ((q = memchr(q, '&', (size_t)(end - q))) != NULL) {
|
|
373
380
|
amp_only.amp++;
|
|
@@ -421,6 +428,7 @@ engine_enter:
|
|
|
421
428
|
if (have_tape) {
|
|
422
429
|
ytap_reset(&yt);
|
|
423
430
|
}
|
|
431
|
+
yep_engine_front_done(eng);
|
|
424
432
|
rc = yep_engine_run(eng, data, data_len, &sink);
|
|
425
433
|
}
|
|
426
434
|
if (rc != 0) {
|
|
@@ -29,6 +29,15 @@ void yep_scan_advance_line(const char* p, size_t* from, size_t to, uint32_t* lin
|
|
|
29
29
|
if (p[i] == '\n') {
|
|
30
30
|
(*line)++;
|
|
31
31
|
*line_start = i + 1;
|
|
32
|
+
} else if (p[i] == '\r' && i + 1 < to && p[i + 1] != '\n') {
|
|
33
|
+
/* a lone \r is a break too (the engine's break rule):
|
|
34
|
+
* the JSON fast path's walk missed it and marked every
|
|
35
|
+
* event after the \r one line low while the general
|
|
36
|
+
* kernel (which walks \r) marked them correctly — whole
|
|
37
|
+
* vs chunked diverged on `\r`-containing JSON-class flow
|
|
38
|
+
* (the nightly's run 38549939326) */
|
|
39
|
+
(*line)++;
|
|
40
|
+
*line_start = i + 1;
|
|
32
41
|
}
|
|
33
42
|
}
|
|
34
43
|
*from = to;
|
|
@@ -151,6 +160,39 @@ size_t yep_scan_prop_end(const char* p, size_t len, size_t pos) {
|
|
|
151
160
|
return pos;
|
|
152
161
|
}
|
|
153
162
|
|
|
163
|
+
int yep_scan_tag_char(unsigned char c) {
|
|
164
|
+
if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
|
|
165
|
+
return 1;
|
|
166
|
+
}
|
|
167
|
+
if (c >= 0x80) {
|
|
168
|
+
return 1; /* UTF-8 suffix bytes pass through */
|
|
169
|
+
}
|
|
170
|
+
switch (c) {
|
|
171
|
+
case '-':
|
|
172
|
+
case '_':
|
|
173
|
+
case ';':
|
|
174
|
+
case '/':
|
|
175
|
+
case '?':
|
|
176
|
+
case ':':
|
|
177
|
+
case '@':
|
|
178
|
+
case '&':
|
|
179
|
+
case '=':
|
|
180
|
+
case '+':
|
|
181
|
+
case '$':
|
|
182
|
+
case '.':
|
|
183
|
+
case '!':
|
|
184
|
+
case '~':
|
|
185
|
+
case '*':
|
|
186
|
+
case '\'':
|
|
187
|
+
case '(':
|
|
188
|
+
case ')':
|
|
189
|
+
case '%':
|
|
190
|
+
return 1;
|
|
191
|
+
default:
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
154
196
|
/* ---- line-shape classification (TODO.restructure/49) ---- */
|
|
155
197
|
|
|
156
198
|
/* blank/EOL/EOF directly after p[at] (the dash / explicit-key rule). */
|
|
@@ -98,6 +98,13 @@ int yep_scan_prop_char(unsigned char c);
|
|
|
98
98
|
/* First offset at/after pos that cannot continue an anchor/alias name. */
|
|
99
99
|
size_t yep_scan_prop_end(const char* p, size_t len, size_t pos);
|
|
100
100
|
|
|
101
|
+
/* Tag-shorthand suffix byte: libyaml's URI set (";/?:@&=+$,_.!~*'()%"
|
|
102
|
+
* plus alphanumerics; flow indicators and ',' terminate instead).
|
|
103
|
+
* Stray non-set bytes stay visible as the props follower, which
|
|
104
|
+
* e_props rejects ("did not find expected whitespace or line break
|
|
105
|
+
* while scanning a tag"). */
|
|
106
|
+
int yep_scan_tag_char(unsigned char c);
|
|
107
|
+
|
|
101
108
|
/* Scans a plain scalar starting at pos (must be content, not a comment).
|
|
102
109
|
* flow != 0 adds flow stop characters; in flow, ':' terminates when
|
|
103
110
|
* followed by blank/EOL/flow indicator. Leading whitespace is NOT
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
#include "common/simd_text.h"
|
|
35
35
|
#include "encoding/encoding.h"
|
|
36
36
|
#include "memory/allocator.h"
|
|
37
|
+
#include "parse/scalars.h"
|
|
37
38
|
#include "scan/json.h"
|
|
38
39
|
|
|
39
40
|
typedef struct {
|
|
@@ -685,6 +686,67 @@ static TAPE_NUM_OK_INLINE int tape_num_ok(const char* p, size_t len) {
|
|
|
685
686
|
return k == len;
|
|
686
687
|
}
|
|
687
688
|
|
|
689
|
+
/* The >1024 simple-key law for the LENIENT walk's tape — the same
|
|
690
|
+
* verdict yt_flow_scan reads for the record walk: a STR at a map's
|
|
691
|
+
* key slot with a raw span past the limit (the law counts the RAW
|
|
692
|
+
* token, so a quoted key's two quotes add back). The DOM route must
|
|
693
|
+
* reject it BEFORE wrapping (strict JSON itself has no limit — the
|
|
694
|
+
* tape API keeps accepting; only the YAML serialization cannot carry
|
|
695
|
+
* a long simple key, so the fast parse defers to the engine's clean
|
|
696
|
+
* error — the nightly's run 38143486175). */
|
|
697
|
+
int yep_tape_long_simple_key(const yeptris_json_tape* s) {
|
|
698
|
+
struct {
|
|
699
|
+
uint8_t map;
|
|
700
|
+
uint8_t key_next;
|
|
701
|
+
} st[257];
|
|
702
|
+
int d = 0;
|
|
703
|
+
st[0].map = 0;
|
|
704
|
+
st[0].key_next = 0;
|
|
705
|
+
for (uint32_t i = 1; i < s->count; i++) { /* recs[0] is the DOC */
|
|
706
|
+
uint64_t r = s->recs[i];
|
|
707
|
+
uint8_t kind = (uint8_t)(r & 0xFFu);
|
|
708
|
+
if (kind == YEP_T_MAP_OPEN || kind == YEP_T_SEQ_OPEN) {
|
|
709
|
+
if (d >= 256) {
|
|
710
|
+
return 1; /* deeper than the scratch stack: over by
|
|
711
|
+
* definition, the engine's depth law decides */
|
|
712
|
+
}
|
|
713
|
+
/* the container consumes the parent frame's pending slot;
|
|
714
|
+
* after it closes the OTHER slot is next (yt_flow_scan's
|
|
715
|
+
* round-108 lesson: a pinned key_next hid every key that
|
|
716
|
+
* followed a container value) */
|
|
717
|
+
if (d > 0 && st[d].map) {
|
|
718
|
+
st[d].key_next = (uint8_t)!st[d].key_next;
|
|
719
|
+
}
|
|
720
|
+
d++;
|
|
721
|
+
st[d].map = (uint8_t)(kind == YEP_T_MAP_OPEN);
|
|
722
|
+
st[d].key_next = 0;
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (kind == YEP_T_CLOSE) {
|
|
726
|
+
if (d > 0) {
|
|
727
|
+
d--;
|
|
728
|
+
}
|
|
729
|
+
continue;
|
|
730
|
+
}
|
|
731
|
+
if (st[d].map && st[d].key_next == 0) {
|
|
732
|
+
uint32_t mlen = (uint32_t)(r >> 8) & 0xFFFFFFu;
|
|
733
|
+
if (kind == YEP_T_STR && mlen + 2u > 1024u &&
|
|
734
|
+
yep_simple_key_chars((const char*)s->_src + (size_t)((uint32_t)(r >> 32)), mlen) +
|
|
735
|
+
2 >
|
|
736
|
+
1024) {
|
|
737
|
+
/* the budget counts characters, not bytes (the round-108
|
|
738
|
+
* shrink: a 2-byte code point at byte delta 1025 is
|
|
739
|
+
* legal); _src rides the walk that produced the tape */
|
|
740
|
+
return 1;
|
|
741
|
+
}
|
|
742
|
+
st[d].key_next = 1;
|
|
743
|
+
} else if (st[d].map) {
|
|
744
|
+
st[d].key_next = 0;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
return 0;
|
|
748
|
+
}
|
|
749
|
+
|
|
688
750
|
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
689
751
|
yeptris_json_tape* t, int strict_nums, int clean_only,
|
|
690
752
|
int reuse_block) {
|
|
@@ -1194,6 +1256,17 @@ ldone:
|
|
|
1194
1256
|
goto lreject;
|
|
1195
1257
|
}
|
|
1196
1258
|
}
|
|
1259
|
+
/* a col-0 tab-led continuation line inside the span is the suite's
|
|
1260
|
+
* Y79Y#4 error: defer to the engine, whose e_flow_ws owns the law
|
|
1261
|
+
* -- the walk's whitespace loops treat the tab as separation, which
|
|
1262
|
+
* accepted exactly the span the marshal drain's engine rejected,
|
|
1263
|
+
* splitting parseable from marshalable (the nightly's round 120) */
|
|
1264
|
+
for (size_t k = open + 1; k < len; k++) {
|
|
1265
|
+
if (p[k] == '\n' && k + 1 < len && p[k + 1] == '\t') {
|
|
1266
|
+
yeptris_tape_free(t);
|
|
1267
|
+
return YEPTRIS_ERROR_PARSE;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1197
1270
|
t->count = count;
|
|
1198
1271
|
t->_src = p;
|
|
1199
1272
|
t->_srclen = len;
|
|
@@ -2013,7 +2086,21 @@ YEPTRIS_API YeptrisStatus yeptris_parse_json_tape_lenient(const char* source, si
|
|
|
2013
2086
|
* 1.65x, json-users 2.2x — the ledger's #85 scoping), and
|
|
2014
2087
|
* this exact call already carried the route's verdicts as the
|
|
2015
2088
|
* escape/C0 fallback, so acceptance is unchanged. */
|
|
2016
|
-
|
|
2089
|
+
int rc = yep_tape_walk_lenient_fused(source, len, at, tape, 0, 0, 0);
|
|
2090
|
+
if (rc != YEPTRIS_OK) {
|
|
2091
|
+
return rc;
|
|
2092
|
+
}
|
|
2093
|
+
/* the YAML simple-key law rides the fused route too: a key
|
|
2094
|
+
* whose raw span crosses 1024 defers to the engine's clean
|
|
2095
|
+
* error — the JSON-class walk has no YAML laws, and the other
|
|
2096
|
+
* routes (engine_run, the marshal drains) reject the same
|
|
2097
|
+
* span, so acceptance here broke whole/chunked marshal parity
|
|
2098
|
+
* (the nightly's round 108) */
|
|
2099
|
+
if (yep_tape_long_simple_key(tape)) {
|
|
2100
|
+
yep_error_set(yep_error_tls(), YEP_ERR_KEY_TOO_LONG, 1, (uint32_t)(at + 1), at, NULL);
|
|
2101
|
+
return YEPTRIS_ERROR_PARSE;
|
|
2102
|
+
}
|
|
2103
|
+
return YEPTRIS_OK;
|
|
2017
2104
|
}
|
|
2018
2105
|
|
|
2019
2106
|
/* scalar root: one record, same deferred split for numbers */
|
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
#include <yeptris/tape.h>
|
|
15
15
|
|
|
16
16
|
/* tape.c (was tape_walk_lnt_fused) */
|
|
17
|
+
int yep_tape_long_simple_key(const yeptris_json_tape* t);
|
|
18
|
+
|
|
17
19
|
YeptrisStatus yep_tape_walk_lenient_fused(const char* p, size_t len, size_t open,
|
|
18
20
|
yeptris_json_tape* t, int strict_nums, int clean_only,
|
|
19
21
|
int reuse_block);
|