yeptris 0.6.52.0-arm-linux-eabihf → 0.6.54.0-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 51f4561549b05fa1678bc7e062857da1c85052810e8db0e4c692182d0c802287
4
- data.tar.gz: 44857029399d44d6c4086c7051da03976c59b5003e4bc2918d91f9df9b4aef07
3
+ metadata.gz: 98eb93f4bcbc15ae9cdbb27ca0c0df3f713f339e5d31a47223410f395b92cb86
4
+ data.tar.gz: 567addfbae19c7b3b3dcf59ff9e073bc3a04372343b965cdd618bea92cbf6cae
5
5
  SHA512:
6
- metadata.gz: faa399d6e06326d9c0a5acddd56f66f200e5263dde33907662108fe5353926e696530e7eaabf11d8a107c32d06134b352b69e0a468bb0fe1d276639897153f9c
7
- data.tar.gz: 428fb4d7027de7f1993e30e3c3bb11e0c2369dee6757f74a9dc2f4fda841527a60e5cebad1b143c936af5de75149b7fe1464477d5d27e452e8dda048ba70064a
6
+ metadata.gz: 6b582fa561076e339b246acac3d9ede1d1b67f31543617df6760c14fe88540938183f4f19ebc5c58a20ff85a288edd993fe39f1a0be6191fd8c78d004b1f42a3
7
+ data.tar.gz: efaf2d6acdc439d85f9a098e4a1dc6b989d8861f25589dd1587bee33a272e41d5e1c8944908d363ab32f1493db6ecd337a06232e574d6247ae1242a34ada17f5
@@ -11,8 +11,8 @@
11
11
 
12
12
  #define YEPTRIS_VERSION_MAJOR 0
13
13
  #define YEPTRIS_VERSION_MINOR 6
14
- #define YEPTRIS_VERSION_PATCH 51
15
- #define YEPTRIS_VERSION_STRING "0.6.51"
14
+ #define YEPTRIS_VERSION_PATCH 54
15
+ #define YEPTRIS_VERSION_STRING "0.6.54"
16
16
 
17
17
  #ifdef __cplusplus
18
18
  extern "C" {
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.6.52.0".freeze
6
+ VERSION = "0.6.54.0".freeze
7
7
 
8
8
  # Informational notices are OPT-IN (yeptris-ruby#217): consumers
9
9
  # embed yeptris inside CLIs that assert clean stderr, and a
data/libyeptris.so CHANGED
Binary file
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.51
6
+ VERSION 0.6.54
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -687,6 +687,13 @@ static int cm_value(cm_ctx* c, cm_buf* out) {
687
687
  return cm_fail(c, YEPTRIS_ERROR_UNSUPPORTED); /* the host loop raises */
688
688
  }
689
689
  double d = strtod(tmp, NULL);
690
+ if (!isfinite(d)) {
691
+ /* the literal spellings gate above; a strtod OVERFLOW
692
+ * ("1e999") manufactures the same non-finite without
693
+ * spelling it — the same strict reject (Ruby streams only
694
+ * ever carry finites or the literal inf/nan spellings) */
695
+ return cm_fail(c, YEPTRIS_ERROR_UNSUPPORTED);
696
+ }
690
697
  uint8_t fw = yep_cbor_float_width(d);
691
698
  if (cm_reserve(c, out, 9) != 0) {
692
699
  return -1;
@@ -92,7 +92,9 @@ static void yep_avx2_copy_count3(char* dst, const char* src, size_t len, char c0
92
92
  memcpy(dst + i, src + i, len - i);
93
93
  }
94
94
  size_t ta = 0, tb = 0, td = 0;
95
- yep_text_count3_scalar(dst + i, len - i, c0, c1, c2, &ta, &tb, &td);
95
+ if (i < len) { /* NULL dst + 0 offset is still UB to form */
96
+ yep_text_count3_scalar(dst + i, len - i, c0, c1, c2, &ta, &tb, &td);
97
+ }
96
98
  *n0 = a + ta;
97
99
  *n1 = b + tb;
98
100
  *n2 = d + td;
@@ -142,14 +142,16 @@ static yep_sview dom_str_in(yep_dom* d, const yep_view* v, int borrowed) {
142
142
  * given metadata; tag/anchor views encode through dom_str_in (tags and
143
143
  * event-path anchors copy to the arena; input-backed views borrow).
144
144
  * tag_id stays 0 — the caller resolves (scalars) or leaves 0. */
145
- /* Value assign + the emit-side fact bit (issue #352 lane 2): the bit
146
- * is "verified clean" of the dq-forced byte set — the serializer's
147
- * sc_route then skips its per-derive rescan. The scan is the SSOT
148
- * predicate (yep_scan_dq_forced); every value assignment routes
145
+ /* Value assign + the emit-side fact bits (issues #352 lanes 2-3):
146
+ * no_exotic is "verified clean" of the dq-forced byte set (sc_route
147
+ * skips its rescan); plain_ok is the full plain-safety verdict (the
148
+ * emitter skips its walk — the block kernel's 35% frame). Both facts
149
+ * ride the scan/'s SSOT predicates; every value assignment routes
149
150
  * through here so no path can leave a dirty scalar marked clean. */
150
151
  static void dom_set_value(yep_dom* d, uint32_t id, const yep_view* v, int borrowed) {
151
152
  d->nodes[id].value = dom_str_in(d, v, borrowed);
152
153
  d->nodes[id].no_exotic = !yep_scan_dq_forced(v->p, v->len);
154
+ d->nodes[id].plain_ok = (uint8_t)yep_scan_plain_safe(v->p, v->len);
153
155
  }
154
156
 
155
157
  uint32_t dom_open_node(yep_dom* d, uint8_t kind, const yep_view* tag, const yep_view* anchor,
@@ -221,8 +223,13 @@ static int dom_anchor_set(yep_dom* d, uint32_t ordinal, uint32_t node) {
221
223
  if (d->anchor_nodes != NULL) {
222
224
  memcpy(na, d->anchor_nodes, d->anchor_nodes_cap * sizeof(*na));
223
225
  yep_free(d->sys, d->anchor_nodes);
224
- yep_free(d->sys, d->mut_att);
225
- yep_free(d->sys, d->mut_depth);
226
+ /* ONLY the anchor table: the mut side tables belong to
227
+ * dom_mut_grow alone (it allocates, copies and frees them
228
+ * together with the cap that tracks their size). These two
229
+ * frees were copy-paste debris from that path -- harmless
230
+ * today only because the mutation tables cannot exist
231
+ * during a parse -- but the ownership must not rely on
232
+ * that accident (audit 2026-10-31). */
226
233
  }
227
234
  d->anchor_nodes = na;
228
235
  d->anchor_nodes_cap = cap;
@@ -1139,7 +1146,7 @@ void dom_on_flow_rollback(void* ctx) {
1139
1146
  * call — the DOM stack mirrors what the MAP_START event would have
1140
1147
  * pushed. 0 only for the depth cap (the engine then takes the events,
1141
1148
  * which own the error). */
1142
- int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t key_col) {
1149
+ int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint32_t key_col) {
1143
1150
  yep_dom* d = (yep_dom*)ctx;
1144
1151
  if (d->depth >= YEP_DOM_MAX_DEPTH) {
1145
1152
  return 0;
@@ -1187,7 +1194,7 @@ int dom_on_block_item(void* ctx, const yep_block_value* v) {
1187
1194
  * happen when the engine resolved the name) falls back to the two
1188
1195
  * events with nothing built. */
1189
1196
  int dom_on_block_pair(void* ctx, const yep_view* key, const yep_block_value* v, uint32_t line,
1190
- uint16_t key_col, uint16_t val_col) {
1197
+ uint32_t key_col, uint32_t val_col) {
1191
1198
  yep_dom* d = (yep_dom*)ctx;
1192
1199
  uint32_t target = 0;
1193
1200
  if (v->cls == YEP_LVAL_ALIAS) {
@@ -68,6 +68,12 @@ typedef struct yep_dnode {
68
68
  * byte set (#352 lane 2): the serializer's
69
69
  * sc_route skips its rescan. Set at every
70
70
  * value assignment; 0 = unknown = scan. */
71
+ uint8_t plain_ok; /* value bytes verified yep_scan_plain_safe
72
+ * (#352 lane 3): the emitter skips its
73
+ * plain-safety walk (the block kernel's 35%
74
+ * frame). Same invariant as no_exotic: set
75
+ * at every dom_set_value; 0 = unknown =
76
+ * derive. */
71
77
  uint8_t tag_id; /* resolved tag (resolve/resolver.h) */
72
78
  uint32_t first_child; /* child link (mappings: key,value,key,value…) */
73
79
  uint32_t last_child;
@@ -283,8 +289,8 @@ int dom_on_scalar(void* ctx, const yep_view* value, const yep_view* tag, const y
283
289
  int borrowed);
284
290
 
285
291
  int dom_on_block_pair(void* ctx, const yep_view* key, const struct yep_block_value* v,
286
- uint32_t line, uint16_t key_col, uint16_t val_col);
287
- int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t key_col);
292
+ uint32_t line, uint32_t key_col, uint32_t val_col);
293
+ int dom_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint32_t key_col);
288
294
  int dom_on_block_item(void* ctx, const yep_block_value* v);
289
295
 
290
296
  /* Direct DOM construction from a strict-validated JSON buffer
@@ -241,7 +241,7 @@ static int yt_on_scalar(void* ctx, const yep_view* value, const yep_view* tag,
241
241
  }
242
242
 
243
243
  static int yt_on_block_pair(void* ctx, const yep_view* key, const yep_block_value* v, uint32_t line,
244
- uint16_t key_col, uint16_t val_col) {
244
+ uint32_t key_col, uint32_t val_col) {
245
245
  (void)line;
246
246
  (void)key_col;
247
247
  (void)val_col; /* yep_dnode carries no positions (64-2c) */
@@ -278,7 +278,7 @@ static int yt_on_block_pair(void* ctx, const yep_view* key, const yep_block_valu
278
278
  return 1; /* handled: the engine skips the two events */
279
279
  }
280
280
 
281
- static int yt_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint16_t key_col) {
281
+ static int yt_on_block_open(void* ctx, const yep_view* key, uint32_t line, uint32_t key_col) {
282
282
  (void)line;
283
283
  (void)key_col;
284
284
  yep_ytape* t = (yep_ytape*)ctx;
@@ -551,6 +551,10 @@ YEPTRIS_API size_t yeptris_serialize_stream(YeptrisDocument handle,
551
551
  return 0;
552
552
  }
553
553
  em.w.p = window;
554
+ /* the writer owns the window size now: wr_put's chunked path and
555
+ * the fused member write bounds-check against it (a scalar larger
556
+ * than the window used to memcpy straight past it) */
557
+ em.w.cap = YEP_EMIT_WATERMARK * 2;
554
558
  em.w.sink_aborted = 0;
555
559
  size_t total = yep_emit_run(&em, 0);
556
560
  if (em.w.len > 0 && !em.w.sink_aborted) {
@@ -1,203 +1,21 @@
1
- /* style.c — the style rule table (TODO.impl/13). */
1
+ /* style.c — the style rule table (TODO.impl/13).
2
+ *
3
+ * The plain-safety predicate LIVES in scan/scan.c (yep_scan_plain_safe,
4
+ * #352 lane 3): bytes→facts is scan/'s alone, and the DOM's parse-time
5
+ * fact bit and this emitter side read the ONE walk so the verdicts
6
+ * cannot drift. These are the emit-side names over it. */
2
7
 
3
8
  #include "style.h"
4
9
 
5
- #include <string.h>
6
-
7
- static int is_blank(char c) {
8
- return c == ' ' || c == '\t';
9
- }
10
-
11
- static int is_break(char c) {
12
- return c == '\n' || c == '\r';
13
- }
10
+ #include "../scan/scan.h"
14
11
 
15
12
  int yep_style_plain_safe(const char* p, uint32_t len) {
16
- if (len == 0) {
17
- return 0; /* empty needs quotes or an empty-value slot */
18
- }
19
- if (is_blank(p[0]) || is_blank(p[len - 1])) {
20
- return 0;
21
- }
22
- if (len >= 3 && (unsigned char)p[0] == 0xef && (unsigned char)p[1] == 0xbb &&
23
- (unsigned char)p[2] == 0xbf) {
24
- /* a LEADING U+FEFF re-parses as a document BOM and vanishes —
25
- * the emitted form must carry its escape ("\uFEFF", the
26
- * nightly's run 38258674337); mid-token BOMs ride plain */
27
- return 0;
28
- }
29
- switch (p[0]) {
30
- case ':':
31
- /* libyaml (Psych symbol dumps ":name"): a leading colon only
32
- * indicates when followed by a blank/EOL — the interior rule
33
- * below covers it; ":name" stays plain */
34
- break;
35
- case '-':
36
- case '?':
37
- /* indicators only before a blank or EOL: "-5" and "?x" are
38
- * plain (libyaml emits negative numbers plain; Psych, too) —
39
- * but fall through: the document-marker check below owns
40
- * the bare "---"/"..." (libyaml quotes those) */
41
- if (len == 1 || is_blank(p[1])) {
42
- return 0;
43
- }
44
- break;
45
- case ',':
46
- case '[':
47
- case ']':
48
- case '{':
49
- case '}':
50
- case '#':
51
- case '&':
52
- case '*':
53
- case '!':
54
- case '|':
55
- case '>':
56
- case '\'':
57
- case '"':
58
- case '%':
59
- case '@':
60
- case '`':
61
- return 0;
62
- default:
63
- break;
64
- }
65
- /* The interior scan in SWAR words: every reject condition is a
66
- * byte-class adjacency, so one masked word test is exact —
67
- * break/tab bytes reject directly; ':' rejects with a blank at its
68
- * NEXT lane (or the span's EOL); '#' with a blank at its PREVIOUS
69
- * lane (the span's first byte is exempt — the head switch already
70
- * handled a leading '#'). Cross-word adjacency rides one carried
71
- * byte per boundary; the tail runs the byte loop, whose rules read
72
- * real neighbors and need no carries. */
73
- {
74
- const uint64_t ONES = 0x0101010101010101ull;
75
- const uint64_t HIGH = 0x8080808080808080ull;
76
- #define YST_ZDET(w, ch) \
77
- ((((w) ^ (uint64_t)(ch) * ONES) - ONES) & ~((w) ^ (uint64_t)(ch) * ONES) & HIGH)
78
- /* the all-boring accept (#742): a span of pure [0-9A-Za-z_]
79
- * makes EVERY rule in this function vacuous — no indicators
80
- * (the head switch), no blanks at the ends, no BOM, no
81
- * ': '/' #' adjacency, no breaks, and no ---/... marker — so
82
- * one range test per word accepts without the six-mask walk.
83
- * Anything else falls through to the exact scan below. */
84
- {
85
- uint32_t bi = 0;
86
- int boring = 1;
87
- while (bi + 8 <= len) {
88
- uint64_t bw;
89
- memcpy(&bw, p + bi, 8);
90
- if (bw & HIGH) {
91
- boring = 0;
92
- break;
93
- }
94
- /* per-lane unsigned range checks via borrow bits: alpha
95
- * is (t - 'a') and ('z' - t) both borrow-free with
96
- * t = w|0x20 (A-Z fold); digits bound 0x30..0x39 */
97
- uint64_t t = bw | (ONES * 0x20);
98
- uint64_t bad = ((t - ONES * 0x61) | (ONES * 0x7A - t)) & HIGH; /* alpha */
99
- bad |= ((bw - ONES * 0x30) | (ONES * 0x39 - bw)) & HIGH; /* digit */
100
- bad &= ~YST_ZDET(bw, '_'); /* the one extra boring byte */
101
- if (bad != 0) {
102
- boring = 0;
103
- break;
104
- }
105
- bi += 8;
106
- }
107
- if (boring) {
108
- for (; bi < len; bi++) {
109
- char c = p[bi];
110
- int a = (c | 0x20);
111
- if (!((c >= '0' && c <= '9') || (a >= 'a' && a <= 'z') || c == '_')) {
112
- boring = 0;
113
- break;
114
- }
115
- }
116
- if (boring) {
117
- return 1;
118
- }
119
- }
120
- }
121
- uint32_t i = 0;
122
- int prev_blank7 = 0;
123
- while (i + 8 <= len) {
124
- uint64_t w;
125
- memcpy(&w, p + i, 8);
126
- if (w & HIGH) {
127
- /* multibyte content: the byte loop owns the rest — a raw
128
- * LS/PS/NEL rides in a scalar value since the quote-aware
129
- * normalizer (#638) and is a line break on re-parse, so
130
- * the value must be quoted, not plain (the nightly's
131
- * round 18, crash-1e79b2e3) */
132
- break;
133
- }
134
- uint64_t space = YST_ZDET(w, ' ');
135
- uint64_t tab = YST_ZDET(w, '\t');
136
- uint64_t blank = space | tab;
137
- uint64_t colon = YST_ZDET(w, ':');
138
- uint64_t hash = YST_ZDET(w, '#');
139
- /* tab and the breaks reject outright */
140
- if (tab | YST_ZDET(w, '\n') | YST_ZDET(w, '\r')) {
141
- return 0;
142
- }
143
- /* ':' + blank next: (blank >> 8) pulls lane i+1's flag down
144
- * into lane i; the word's last lane takes the peeked byte
145
- * (EOL at the span end counts as blank — the rule rejects
146
- * there) */
147
- if (colon) {
148
- int next_blank = i + 8 < len ? is_blank(p[i + 8]) : 1;
149
- if (colon & ((blank >> 8) | (next_blank ? (uint64_t)0x80 << 56 : 0))) {
150
- return 0;
151
- }
152
- }
153
- /* '#' + blank prev: (blank << 8) lifts lane i-1's flag up
154
- * into lane i; lane 0 takes the carried last-lane flag */
155
- if (hash && (hash & ((blank << 8) | (prev_blank7 ? 0x80 : 0)))) {
156
- return 0;
157
- }
158
- prev_blank7 = (int)((blank >> 63) & 1); /* lane 7's flag is its top bit */
159
- i += 8;
160
- }
161
- #undef YST_ZDET
162
- for (; i < len; i++) {
163
- char c = p[i];
164
- if (is_break(c) || c == '\t') {
165
- return 0;
166
- }
167
- if ((unsigned char)c == 0xE2 && i + 2 < len && (unsigned char)p[i + 1] == 0x80 &&
168
- ((unsigned char)p[i + 2] & 0xFE) == 0xA8) {
169
- return 0; /* a raw LS/PS re-parses as a line break */
170
- }
171
- if ((unsigned char)c == 0xC2 && i + 1 < len && (unsigned char)p[i + 1] == 0x85) {
172
- return 0; /* a raw NEL ditto */
173
- }
174
- if (c == ':') {
175
- if (i + 1 >= len || is_blank(p[i + 1])) {
176
- return 0;
177
- }
178
- }
179
- if (c == '#') {
180
- if (i > 0 && is_blank(p[i - 1])) {
181
- return 0;
182
- }
183
- }
184
- }
185
- }
186
- /* document markers */
187
- if (len >= 3 && (memcmp(p, "---", 3) == 0 || memcmp(p, "...", 3) == 0) &&
188
- (len == 3 || p[3] == ' ' || p[3] == '\t' || p[3] == '\n' || p[3] == '\r')) {
189
- /* a PREFIX marker is worse than the bare one: emitted plain at
190
- * line start, "--- ..." re-reads as a document marker (the
191
- * nightly's "--- --- >" folded-plain crasher) — libyaml quotes
192
- * both */
193
- return 0;
194
- }
195
- return 1;
13
+ return yep_scan_plain_safe(p, len);
196
14
  }
197
15
 
198
16
  int yep_style_plain_key_safe(const char* p, uint32_t len) {
199
17
  /* plain_safe's colon rule is the key rule too: a colon only ends a
200
18
  * key when followed by a blank/EOL, so "a:b" and ":name" are plain
201
19
  * keys (libyaml emits Psych's symbol dumps exactly this way) */
202
- return yep_style_plain_safe(p, len);
20
+ return yep_scan_plain_safe(p, len);
203
21
  }