yeptris 0.6.30.1-powerpc64le-linux → 0.6.31.2-powerpc64le-linux

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: 57222d99a292ca313a29dd6e849ce9bf42881805c61888c4b554e472b6c9b780
4
- data.tar.gz: 9cb6e71e7e624320f131eddf9d1a702d9a9471948e4a3d7ae04cef8657d6a54b
3
+ metadata.gz: 0e9688f533c0a29fb0ab4447d915cebc3b49b2ef4b7fd89ccd01b8987ac306e9
4
+ data.tar.gz: 505362de7b095d280bd29d664d4bac1111743d70eec13a391937c4425dc77a38
5
5
  SHA512:
6
- metadata.gz: a98785e26ecf1c2d9b4390b93a027045281664f3ff085165b2f80d471e47ce9825d8d92ba872f3232ee3cb8f47b14e34e24f37ab43556b45f2c917111117427a
7
- data.tar.gz: 04f99c910d23c9c354382a53dc47f535019e0f841859c9d9e3eb5ade1892d5df2b69d98421239aaf8de9d1ea5d39ce440a224c9a98121cd9baff6500effef71b
6
+ metadata.gz: 4fd7a0e32448ae590f0656fc46f5fcccabd80a6253fffcf57a730de3ab6453fa92d6750532bfedacea398ddc9d865e3e7743afd1356f82f7c34387f5b66cb3a5
7
+ data.tar.gz: b9c26e0e5c8f20d0b688bead87ce58f3c9ce9ffbe9634393732ca2f45713f999b29e356aecc09df7a364cf3d2278e9c2e2eec1f9e289cb35272522999463da5f
data/lib/yeptris/yaml.rb CHANGED
@@ -263,7 +263,7 @@ module Yeptris
263
263
  return true
264
264
  end
265
265
  return false if s.empty? || s != s.strip
266
- return false if s.match?(/[\n\t]/)
266
+ return false if s.match?(/[\n\t\u0085\u2028\u2029\uFEFF]/)
267
267
  c = s[0]
268
268
  return false if "#,[]{}&*!|>'\"%@`".include?(c)
269
269
  return false if "-?:".include?(c) && (s.length == 1 || s[1] =~ /[ \t]/)
@@ -309,7 +309,12 @@ module Yeptris
309
309
  return :double if !s.empty? && !s.include?('"') && s.match?(/\A[^[:word:]]/)
310
310
  return :single if s.match?(/\A0[0-7]*[89]/)
311
311
  return :plain if plain_string?(s)
312
+ # the Unicode breaks are YAML breaks like \n (raw, re-parse
313
+ # folds them) and U+FEFF raw is the BOM (re-parse strips it) —
314
+ # only the double-quoted escapes carry them byte-stably; psych
315
+ # double-quotes them all (Psych.dump("b\u0085c") == "b\\Nb")
312
316
  return :double if s.each_byte.any? { |b| b < 0x20 || b == 0x7f }
317
+ return :double if s.match?(/[\u0085\u2028\u2029\uFEFF]/)
313
318
  :single
314
319
  end
315
320
 
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.30.1".freeze
6
+ VERSION = "0.6.31.2".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.30
6
+ VERSION 0.6.31
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -100,8 +100,12 @@ endif()
100
100
 
101
101
  # libFuzzer implies ASAN (libleptris TODO 40 pattern).
102
102
  if(YEPTRIS_ENABLE_FUZZING)
103
+ # instrument everything, but link the fuzzer MAIN only into the
104
+ # harnesses: a global -fsanitize=fuzzer link option demands
105
+ # LLVMFuzzerTestOneInput from every executable (the CLI and the
106
+ # test binaries died on it once CXX also pinned to clang++)
103
107
  add_compile_options(-fsanitize=fuzzer-no-link,address -fno-omit-frame-pointer -g)
104
- add_link_options(-fsanitize=fuzzer,address)
108
+ add_link_options(-fsanitize=address)
105
109
  message(STATUS "libFuzzer: ENABLED (implies ASAN)")
106
110
  endif()
107
111
 
@@ -179,6 +179,11 @@ static ptrdiff_t yep_avx2_quote_scan(const char* s, size_t len, char q, int* has
179
179
  }
180
180
  return (ptrdiff_t)(i + k);
181
181
  }
182
+ if (i >= len) {
183
+ break; /* an escape at the boundary consumed the rest: unterminated
184
+ * (a lone '\' as the last byte pushed i past len; the tail
185
+ * call would underflow len - i and read out of bounds) */
186
+ }
182
187
  if (i + YEP_AVX2_CHUNK > len) {
183
188
  int tail_esc = 0;
184
189
  ptrdiff_t r = yep_text_quote_scan_scalar(s + i, len - i, q, &tail_esc);
@@ -1422,7 +1422,8 @@ static int yt_f_run(yt_fused* F) {
1422
1422
  (line_stop + 1 >= line_end || p[line_stop + 1] == ' ' ||
1423
1423
  p[line_stop + 1] == '\t') &&
1424
1424
  !(c == '&' || c == '!' || c == '*' || c == '\'' || c == '"' || c == '[' ||
1425
- c == '{' || c == '|' || c == '>' || c == '%' || c == '?' || c == '-')) {
1425
+ c == '{' || c == '|' || c == '>' || c == '%' || c == '?' || c == '-') &&
1426
+ yep_plain_first_ok((unsigned char)c)) {
1426
1427
  uint32_t kend = line_stop;
1427
1428
  while (kend > t0 && (p[kend - 1] == ' ' || p[kend - 1] == '\t')) {
1428
1429
  kend--;
@@ -1450,6 +1451,10 @@ static int yt_f_run(yt_fused* F) {
1450
1451
  }
1451
1452
  aoff = (uint32_t)(vt + 1);
1452
1453
  alen = (uint32_t)(ne - vt - 1);
1454
+ if (alen == 0) {
1455
+ return 1; /* an anchor needs a name (libyaml):
1456
+ the engine owns the error */
1457
+ }
1453
1458
  F->anchor_seq++;
1454
1459
  aid = F->anchor_seq;
1455
1460
  if (!yt_anchor_table(F)) {
@@ -1810,13 +1815,20 @@ static int yt_f_run(yt_fused* F) {
1810
1815
  goto line_done;
1811
1816
  }
1812
1817
  if (vc == '"' || vc == '\'' || vc == '|' || vc == '>' || vc == '[' ||
1813
- vc == '{' || vc == '!' || vc == '%') {
1814
- return 1; /* quoted/block/flow/tag values: the engine */
1818
+ vc == '{' || vc == '!' || vc == '%' || vc == '&' || vc == '*') {
1819
+ return 1; /* quoted/block/flow/tag/anchor/alias values:
1820
+ the engine */
1815
1821
  }
1816
1822
  if ((vc == '-' || vc == '?') && (vt + 1 >= line_end || p[vt + 1] == ' ' ||
1817
1823
  p[vt + 1] == '\t' || p[vt + 1] == '#')) {
1818
1824
  return 1; /* an indicator-as-value: the engine errors */
1819
1825
  }
1826
+ if (!yep_plain_first_ok(vc)) {
1827
+ return 1; /* '}' ']' ',' '@' '`' '%': no node
1828
+ * content can start there (the nightly's
1829
+ * fuzz_roundtrip crasher, "u: }") — the engine
1830
+ * errors cleanly */
1831
+ }
1820
1832
  /* a terminating ':' inside the value is the
1821
1833
  * mapping-values error — the engine owns it */
1822
1834
  for (const char* h = (const char*)memchr(p + vt, ':', line_end - vt);
@@ -142,6 +142,45 @@ static void emit_dq(yep_writer* w, const char* p, uint32_t n) {
142
142
  uint32_t run = 0;
143
143
  for (uint32_t i = 0; i < n; i++) {
144
144
  unsigned char c = (unsigned char)p[i];
145
+ /* U+0085 (NEL) is a BREAK in YAML: raw it would fold on
146
+ * re-parse. Escape it ('\N' replaces the exact UTF-8 pair, so
147
+ * lengths stay equal). The nightly's fuzz_roundtrip
148
+ * byte-instability crasher, "\"1 \\N\"". */
149
+ if (c == 0xc2 && i + 1 < n && (unsigned char)p[i + 1] == 0x85) {
150
+ if (run) {
151
+ wr_put(w, p + i - run, run);
152
+ run = 0;
153
+ }
154
+ wr_put(w, "\\N", 2);
155
+ i++;
156
+ continue;
157
+ }
158
+ /* LS/PS (U+2028/U+2029) are libyaml breaks: raw, re-parse
159
+ * folds them (the nightly's ";\\P" catch). 2-char escapes of
160
+ * 3-byte sequences: the one-pass dry count sizes them. */
161
+ if (c == 0xe2 && i + 2 < n && (unsigned char)p[i + 1] == 0x80 &&
162
+ ((unsigned char)p[i + 2] == 0xa8 || (unsigned char)p[i + 2] == 0xa9)) {
163
+ if (run) {
164
+ wr_put(w, p + i - run, run);
165
+ run = 0;
166
+ }
167
+ wr_put(w, (unsigned char)p[i + 2] == 0xa8 ? "\\L" : "\\P", 2);
168
+ i += 2;
169
+ continue;
170
+ }
171
+ /* U+FEFF must never ride raw: at the buffer head it IS the
172
+ * BOM and re-parse would strip it (the nightly's UTF-32LE
173
+ * catch); Psych escapes it everywhere ("") */
174
+ if (c == 0xef && i + 2 < n && (unsigned char)p[i + 1] == 0xbb &&
175
+ (unsigned char)p[i + 2] == 0xbf) {
176
+ if (run) {
177
+ wr_put(w, p + i - run, run);
178
+ run = 0;
179
+ }
180
+ wr_put(w, "\\uFEFF", 6);
181
+ i += 2;
182
+ continue;
183
+ }
145
184
  if (c >= 0x20 && c != '"' && c != '\\' && c != 0x7f) {
146
185
  run++;
147
186
  continue;
@@ -330,6 +369,34 @@ enum { YEP_SC_NOTHING = 0, YEP_SC_PLAIN, YEP_SC_SQ, YEP_SC_DQ, YEP_SC_LITERAL };
330
369
 
331
370
  static uint8_t sc_route(yep_writer* w, const char* p, uint32_t len, int as_key, uint8_t sty_in,
332
371
  int has_tag) {
372
+ /* U+0085 is a break (only its \\N escape is byte-stable) and U+FEFF
373
+ * raw is the BOM (re-parse would strip it): both force the
374
+ * double-quoted route BEFORE the plain fast path can take them
375
+ * (the nightly's fuzz_roundtrip crashers). The NEL scan matches
376
+ * the UTF-8 PAIR only — a lone 0x85 is a continuation byte
377
+ * (U+315B = E3 85 9B). */
378
+ int has_nel = 0;
379
+ int has_bom = 0;
380
+ for (uint32_t k = 0; k + 1 < len; k++) {
381
+ if ((unsigned char)p[k] == 0xc2 && (unsigned char)p[k + 1] == 0x85) {
382
+ has_nel = 1;
383
+ break;
384
+ }
385
+ /* LS/PS are breaks like NEL: only their escapes are stable */
386
+ if ((unsigned char)p[k] == 0xe2 && k + 2 < len && (unsigned char)p[k + 1] == 0x80 &&
387
+ ((unsigned char)p[k + 2] == 0xa8 || (unsigned char)p[k + 2] == 0xa9)) {
388
+ has_nel = 1;
389
+ break;
390
+ }
391
+ if ((unsigned char)p[k] == 0xef && k + 2 < len && (unsigned char)p[k + 1] == 0xbb &&
392
+ (unsigned char)p[k + 2] == 0xbf) {
393
+ has_bom = 1;
394
+ break;
395
+ }
396
+ }
397
+ if (has_nel || has_bom) {
398
+ return YEP_SC_DQ;
399
+ }
333
400
  if ((sty_in == 1) && len > 0 &&
334
401
  (as_key ? yep_style_plain_key_safe(p, len) : yep_style_plain_safe(p, len))) {
335
402
  return YEP_SC_PLAIN; /* plain-safe implies no breaks: memchr skipped */
@@ -119,6 +119,11 @@ struct yep_engine {
119
119
  char* norm_buf; /* owned input copy with exotic breaks normalized */
120
120
  const struct yep_resolver* resolver; /* implicit-typing schema (10) */
121
121
  int max_depth; /* runtime nesting limit (options) */
122
+ uint16_t rec; /* e_node<->e_parse_value call depth:
123
+ the props/value-line chain opens NO
124
+ container frame, so e->depth cannot
125
+ bound it (the nightly's stack
126
+ overflow crasher) */
122
127
  int last_root_flow; /* a root-level flow node just completed */
123
128
  int tag_undef; /* an unresolved !handle! was seen (QLJ7) */
124
129
  int doc_inline; /* content node opened on the --- line */
@@ -1090,16 +1095,32 @@ static void e_props(yep_engine* e, yep_view* anchor, yep_view* tag) {
1090
1095
  e->pos = yep_scan_prop_end(e->p, e->len, start);
1091
1096
  anchor->p = e->p + start;
1092
1097
  anchor->len = (uint32_t)(e->pos - start);
1098
+ if (anchor->len == 0) {
1099
+ /* libyaml requires one or more anchor characters
1100
+ * ("did not find expected alphabetic or numeric
1101
+ * character"); the nightly fuzz_roundtrip crasher,
1102
+ * a lone '&' */
1103
+ e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
1104
+ return;
1105
+ }
1093
1106
  } else if (c == '!') {
1094
1107
  size_t start = e->pos;
1095
1108
  e->pos++;
1096
1109
  if (e->pos < e->len && e->p[e->pos] == '<') {
1097
- while (e->pos < e->len && e->p[e->pos] != '>') {
1098
- e->pos++;
1099
- }
1100
- if (e->pos < e->len) {
1101
- e->pos++;
1102
- }
1110
+ /* a verbatim tag closes '>' on the same line, with no
1111
+ * interior space and non-empty content — libyaml errors
1112
+ * otherwise ("did not find expected '>'"; the nightly's
1113
+ * fuzz_roundtrip byte-instability crasher, "!<") */
1114
+ size_t gt = e->pos + 1;
1115
+ while (gt < e->len && e->p[gt] != '>' && e->p[gt] != '\n' && e->p[gt] != '\r' &&
1116
+ e->p[gt] != ' ' && e->p[gt] != '\t') {
1117
+ gt++;
1118
+ }
1119
+ if (gt >= e->len || e->p[gt] != '>' || gt == e->pos + 1) {
1120
+ e_fail(e, YEP_ERR_UNEXPECTED, start);
1121
+ return;
1122
+ }
1123
+ e->pos = gt + 1;
1103
1124
  } else {
1104
1125
  while (e->pos < e->len && yep_scan_prop_char((unsigned char)e->p[e->pos])) {
1105
1126
  e->pos++;
@@ -1282,6 +1303,9 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
1282
1303
  ev->col = e_col(e, e->pos) + 1;
1283
1304
  yep_view anchor = {0}, tag = {0};
1284
1305
  e_props(e, &anchor, &tag);
1306
+ if (e->err.code != YEP_ERR_NONE) {
1307
+ return -1; /* e_props failed (empty anchor name, unresolved tag) */
1308
+ }
1285
1309
  ev->anchor = anchor;
1286
1310
  ev->tag = tag;
1287
1311
  if (!yep_view_is_empty(anchor)) {
@@ -1290,10 +1314,17 @@ static int e_flow_node(yep_engine* e, yep_event* ev, int keyish) {
1290
1314
  if (e_flow_ws(e) != 0) {
1291
1315
  return -1;
1292
1316
  }
1317
+ if (e->pos >= e->len) {
1318
+ /* props at EOF: no node follows the properties (the entry
1319
+ * guard above cannot cover this — e_props consumed to the
1320
+ * end; found by fuzz_parse, input "[!<<\r\n!]" x8) */
1321
+ return e_fail(e, YEP_ERR_UNEXPECTED, e->pos);
1322
+ }
1293
1323
  c = (unsigned char)e->p[e->pos];
1294
1324
  if ((c == ',' || c == ']' || c == '}' || c == ':') &&
1295
1325
  (!yep_view_is_empty(anchor) || !yep_view_is_empty(tag))) {
1296
1326
  ev->implicit = 1; /* properties with no node: a tagged null */
1327
+ ev->style = YEP_STYLE_PLAIN;
1297
1328
  e_pos_mark(e, e->pos, &ev->end_line, &ev->end_col);
1298
1329
  return 1;
1299
1330
  }
@@ -1813,6 +1844,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
1813
1844
  /* '? : v' / '?' at the boundary: an EMPTY explicit key */
1814
1845
  e_event_init(&ev, YEP_EV_SCALAR);
1815
1846
  ev.implicit = 1;
1847
+ ev.style = YEP_STYLE_PLAIN;
1816
1848
  ev.line = e->line;
1817
1849
  ev.col = e_col(e, e->pos) + 1;
1818
1850
  rc = 1;
@@ -1984,6 +2016,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
1984
2016
  yep_event nv;
1985
2017
  e_event_init(&nv, YEP_EV_SCALAR);
1986
2018
  nv.implicit = 1;
2019
+ nv.style = YEP_STYLE_PLAIN;
1987
2020
  if (emit_now(e, &nv) != 0) {
1988
2021
  return -2;
1989
2022
  }
@@ -2026,6 +2059,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2026
2059
  yep_event nv;
2027
2060
  e_event_init(&nv, YEP_EV_SCALAR);
2028
2061
  nv.implicit = 1;
2062
+ nv.style = YEP_STYLE_PLAIN;
2029
2063
  if (emit_now(e, &nv) != 0) {
2030
2064
  return -2;
2031
2065
  }
@@ -2059,6 +2093,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2059
2093
  yep_event nv;
2060
2094
  e_event_init(&nv, YEP_EV_SCALAR);
2061
2095
  nv.implicit = 1;
2096
+ nv.style = YEP_STYLE_PLAIN;
2062
2097
  if (emit_now(e, &nv) != 0) {
2063
2098
  return -2;
2064
2099
  }
@@ -2076,6 +2111,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2076
2111
  yep_event nv;
2077
2112
  e_event_init(&nv, YEP_EV_SCALAR);
2078
2113
  nv.implicit = 1;
2114
+ nv.style = YEP_STYLE_PLAIN;
2079
2115
  if (emit_now(e, &nv) != 0) {
2080
2116
  return -2;
2081
2117
  }
@@ -2104,6 +2140,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2104
2140
  yep_event nv;
2105
2141
  e_event_init(&nv, YEP_EV_SCALAR);
2106
2142
  nv.implicit = 1;
2143
+ nv.style = YEP_STYLE_PLAIN;
2107
2144
  if (emit_now(e, &nv) != 0) {
2108
2145
  return -2;
2109
2146
  }
@@ -2114,6 +2151,7 @@ static int e_flow(yep_engine* e, yep_view anchor, yep_view tag, uint32_t anchor_
2114
2151
  yep_event nv;
2115
2152
  e_event_init(&nv, YEP_EV_SCALAR);
2116
2153
  nv.implicit = 1;
2154
+ nv.style = YEP_STYLE_PLAIN;
2117
2155
  if (emit_now(e, &nv) != 0) {
2118
2156
  return -2;
2119
2157
  }
@@ -2657,7 +2695,13 @@ static int e_node(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
2657
2695
  e->pend_anchor_id = anchor_ordinal;
2658
2696
  e->pend_tag = node_t;
2659
2697
  e->doc_inline = 0; /* the node starts on a later line */
2660
- return e_parse_value(e, ctx, floor_col);
2698
+ if (++e->rec >= e->max_depth) {
2699
+ e->rec--;
2700
+ return e_fail(e, YEP_ERR_DEPTH, e->pos);
2701
+ }
2702
+ int rc = e_parse_value(e, ctx, floor_col);
2703
+ e->rec--;
2704
+ return rc;
2661
2705
  /* (ctx stays: AFTER_COLON converts to VALUE_LINE at the break) */
2662
2706
  }
2663
2707
 
@@ -3069,7 +3113,15 @@ static int e_parse_value(yep_engine* e, yep_ctx ctx, uint16_t floor_col) {
3069
3113
  (vctx == YEP_CTX_VALUE_LINE && (li.first == '|' || li.first == '>') &&
3070
3114
  li.indent == floor_col)) {
3071
3115
  e->pos += li.indent;
3072
- return e_node(e, vctx, floor_col);
3116
+ if (++e->rec >= e->max_depth) {
3117
+ e->rec--;
3118
+ return e_fail(e, YEP_ERR_DEPTH, e->pos);
3119
+ }
3120
+ {
3121
+ int rc = e_node(e, vctx, floor_col);
3122
+ e->rec--;
3123
+ return rc;
3124
+ }
3073
3125
  }
3074
3126
  /* indentless sequence as a mapping value; under a sequence frame
3075
3127
  * a dash at the same column is a SIBLING, not a continuation */
@@ -199,6 +199,10 @@ static void shape_value(const char* p, size_t len, const yep_line_info* li, size
199
199
  }
200
200
  if (c == '&') {
201
201
  size_t a_end = yep_scan_prop_end(p, len, vt + 1);
202
+ if (a_end == vt + 1) {
203
+ return; /* an anchor needs a name (libyaml): the general
204
+ * chain owns the error */
205
+ }
202
206
  size_t t = a_end;
203
207
  while (t < len && (p[t] == ' ' || p[t] == '\t')) {
204
208
  t++;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yeptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.30.1
4
+ version: 0.6.31.2
5
5
  platform: powerpc64le-linux
6
6
  authors:
7
7
  - Ribose Inc.