ox 2.14.28 → 2.14.29

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: 55a1d3d6cf3b51d434dc27e11ac62c93b2eab2b08426daf03c13f295b43cdd5e
4
- data.tar.gz: 17b62fcfb67d670bf3693b6863d3906cd52a5f61b0344d5aa5fd1ed8dda26584
3
+ metadata.gz: 8ebfb30efd11a67a36973ca7fd8ada6eb2d193a0667882ccb78498cdb1362f32
4
+ data.tar.gz: a1a41cceb0750adc25b6ee9dff8d7b4c2921e6335ba49e1a2daac3de39f98d16
5
5
  SHA512:
6
- metadata.gz: c063a565a7dc1f1edd042377fbf195d53533a8a3d1585f3a29455beefb9cc7d4c6e9e4911c4632ee48c45f67b4a16b34c8cde7fbcb5aa5c63db74240e7d72230
7
- data.tar.gz: 4338c45e7ea8c81948d0dc44af7244593fd0594b9c6c38ffddd1bd247baaa1369e856b8604e09419f8c035cc36478a633d50c005c171ecc4d054c2def302d53a
6
+ metadata.gz: dfe7978d1f1164cdd391229803e960f929db444021ede9397e689624721b59aec4e92cbee41805d1ddf1272d04526d795a739708e386463c23240431cafd9f1b
7
+ data.tar.gz: 119ca72c836197ef6d8dcd8c259b1e198563c3b94f5aac6baec45b54db3e8dfc5aa84d763d2044e8ed2173d9451806aa9a9b3a925bc95ed5c6ffffbdcc5e8cf7
data/CHANGELOG.md CHANGED
@@ -2,6 +2,109 @@
2
2
 
3
3
  All changes to the Ox gem are documented here. Releases follow semantic versioning.
4
4
 
5
+ ## [2.14.29] - 2026-07-08
6
+
7
+ ### Added
8
+
9
+ - Speed up Ox.dump by not type checking the same String twice. See PR #471.
10
+ - Speed up Ox.dump / Ox::Builder string escaping with a SWAR fast path.
11
+ See PR #423.
12
+ - Speed up Ox.load text parsing with a SWAR fast path. See PR #421.
13
+ - Speed up Ox.dump integer serialization. See PR #417.
14
+ - Speed up Ox.dump string and indent writing. See PR #416.
15
+ - Port oj's fast_memcpy16 into the Ox.dump short-copy path. See PR #424.
16
+ - Drop a redundant strlen and newline scan from text node parsing.
17
+ See PR #422.
18
+ - Added ruby_memcheck (Valgrind memcheck) integration as rake test:valgrind.
19
+ See PR #426.
20
+ - Added Valgrind memcheck CI workflow. See PR #427.
21
+ - Added a 20 minute timeout to the CI and Valgrind jobs. See PR #432.
22
+ - Limited the CI workflows to a read-only token and stopped persisting
23
+ it. See PR #436.
24
+
25
+ ### Changed
26
+
27
+ - An `<?ox mode="object"?>` processing instruction in a document no
28
+ longer switches a default `Ox.load` into object mode. Object mode
29
+ allocates the classes the document names without calling `initialize`
30
+ and sets their instance variables, so a document can no longer ask for
31
+ that on its own. Pass `mode: :object` to load in object mode.
32
+ `mode="generic"` and `mode="limited"` are unaffected. See issue #446.
33
+
34
+ - Use rb_range_values() to dump a Range instead of struct slots. See PR #429.
35
+ - Removed the dead buf_reset() from the builder's buf.h. See PR #453.
36
+
37
+ ### Fixed
38
+
39
+ - Fix an element or attribute name going out unchecked. A name can now
40
+ end itself and start something else with nothing raised. See PR #470.
41
+ - Fix a comment, CDATA, DOCTYPE or instruction value going out
42
+ unchecked. A NUL in these nodes could lose data. See PR #468.
43
+ - Fix Ox::Builder counting more than it writes, and to_s writing to the
44
+ buffer. See PR #467.
45
+ - Fix :invalid_replace having no effect unless :effort is moved. See
46
+ PR #466.
47
+ - Fix a rescued raise leaving part of the value in the buffer. See
48
+ PR #465.
49
+ - Fix a slash in a Regexp pattern coming back escaped. See PR #463.
50
+ - Fix the arity -1 entry points reading past their arguments. See PR #462.
51
+ - Fix a Symbol name being truncated at an embedded NUL. See PR #461.
52
+ - Fix an encoding set in Ox.default_options never being cleared. See
53
+ PR #459.
54
+ - Fix Ox::Builder truncating a value at an embedded NUL. See PR #458.
55
+ - Fix a loaded Regexp ignoring the document's encoding. See PR #457.
56
+ - Fix the xsd dateTime conversion discarding the timezone offset. See
57
+ PR #456.
58
+ - Fix parse_regexp building a pointer before the start of its text. See
59
+ PR #455.
60
+ - Fix a :nest_ok comment being dropped inside an :off element. See PR #454.
61
+ - Fix Ox.load_file failing on Windows for files ox wrote itself. See
62
+ PR #452.
63
+ - Fix the builder output buffer being freed with the wrong allocator.
64
+ See PR #451.
65
+ - Fix a CDATA value being able to close its own section. See PR #450.
66
+ - Fix buffer over-read of an Ox::Builder element name that holds a NUL.
67
+ See PR #449.
68
+ - Fix a memory leak when an `<?ox mode?>` processing instruction
69
+ appears more than sixteen elements deep in a document.
70
+ - Fix the SAX parser reading uninitialised memory after EOF on a file.
71
+ See PR #447.
72
+ - Fix the double free of the hash mode mark list. See PR #445.
73
+ - Fix the sample XML files carrying what look like real passwords. See
74
+ PR #444.
75
+ - Fix the heap overflow and the stale element name in dump_gen_element.
76
+ See PR #443.
77
+ - Fix SEGV when an object mode container is not what end_element
78
+ expects. See PR #442.
79
+ - Fix the thin time format losing times before 1970 and after 2038. See
80
+ PR #438.
81
+ - Fix Ox.load_file sizing the read from whatever the path reports. See
82
+ PR #441.
83
+ - Fix the name cache pointer held across callbacks and the unchecked
84
+ allocations. See PR #440.
85
+ - Fix the out-of-bounds read and write in the base64 decode. See PR #439.
86
+ - Fix SEGV when dumping a Time localtime() can not represent. See
87
+ PR #437.
88
+ - Fix out-of-bounds heap write and read in the circular reference table.
89
+ See PR #434.
90
+ - Fix hash flooding by seeding the name cache hash per process. See
91
+ PR #435.
92
+ - Fix memory leak of the object-mode circular reference table. See
93
+ PR #433.
94
+ - Fix rake test_all silently skipping most of the test suite. See PR #431.
95
+ - Fix memory leaks on parse error paths, the SAX element stack, and the
96
+ intern cache. See PR #428.
97
+ - Fix heap out-of-bounds read and write after the Ox::Builder depth
98
+ raise. See PR #430.
99
+ - Free the Ox.dump output buffer when a dump raises. See PR #425.
100
+ - Fix GC crash from stack PInfo wrapper left dangling on a raised parse.
101
+ See PR #420.
102
+ - Fix xml_str_len returning ~49x the escaped length. See PR #419.
103
+ - Limit sax nesting. See PR #418.
104
+ - Fix integer overflow with oversized dump :indent option. See PR #415.
105
+ - Fix stack buffer overflow on long object-mode class names. See PR #414.
106
+ - Fix buffer overflow in SAX IO read callbacks. See PR #413.
107
+
5
108
  ## [2.14.28] - 2026-06-28
6
109
 
7
110
  ### Fixed
data/ext/ox/base64.c CHANGED
@@ -61,30 +61,30 @@ void to_base64(const uchar *src, int len, char *b64) {
61
61
  *b64 = '\0';
62
62
  }
63
63
 
64
+ // Bytes from_base64() will write, not counting the terminator. It stops where
65
+ // from_base64() stops instead of measuring the string, so the two can not
66
+ // disagree about where the encoding ends.
64
67
  unsigned long b64_orig_size(const char *text) {
65
68
  const char *start = text;
66
- unsigned long size = 0;
69
+ unsigned long cnt;
67
70
 
68
- if ('\0' != *text) {
69
- for (; 0 != *text; text++) {
70
- }
71
- size = (text - start) * 3 / 4;
72
- text--;
73
- if ('=' == *text) {
74
- size--;
75
- text--;
76
- if ('=' == *text) {
77
- size--;
78
- }
79
- }
71
+ for (; 'X' != s_digits[(uchar)*text]; text++) {
80
72
  }
81
- return size;
73
+ cnt = (unsigned long)(text - start);
74
+
75
+ // Four characters carry three bytes. A trailing pair or triple carries one
76
+ // or two, a trailing single character none.
77
+ return cnt / 4 * 3 + (2 <= cnt % 4 ? cnt % 4 - 1 : 0);
82
78
  }
83
79
 
84
- void from_base64(const char *b64, uchar *str) {
85
- uchar b0, b1, b2, b3;
80
+ // size counts the terminator. It is honoured even if it disagrees with
81
+ // b64_orig_size(), so the two can not drift back into an overflow.
82
+ unsigned long from_base64(const char *b64, uchar *str, unsigned long size) {
83
+ uchar *start = str;
84
+ uchar *end = str + size - 1;
85
+ uchar b0, b1, b2, b3;
86
86
 
87
- while (1) {
87
+ while (str < end) {
88
88
  if ('X' == (b0 = s_digits[(uchar)*b64++])) {
89
89
  break;
90
90
  }
@@ -92,14 +92,21 @@ void from_base64(const char *b64, uchar *str) {
92
92
  break;
93
93
  }
94
94
  *str++ = (b0 << 2) | ((b1 >> 4) & 0x03);
95
+ if (end <= str) {
96
+ break;
97
+ }
95
98
  if ('X' == (b2 = s_digits[(uchar)*b64++])) {
96
99
  break;
97
100
  }
98
101
  *str++ = (b1 << 4) | ((b2 >> 2) & 0x0F);
102
+ if (end <= str) {
103
+ break;
104
+ }
99
105
  if ('X' == (b3 = s_digits[(uchar)*b64++])) {
100
106
  break;
101
107
  }
102
108
  *str++ = (b2 << 6) | b3;
103
109
  }
104
110
  *str = '\0';
111
+ return (unsigned long)(str - start);
105
112
  }
data/ext/ox/base64.h CHANGED
@@ -13,6 +13,7 @@ typedef unsigned char uchar;
13
13
  extern unsigned long b64_orig_size(const char *text);
14
14
 
15
15
  extern void to_base64(const uchar *src, int len, char *b64);
16
- extern void from_base64(const char *b64, uchar *str);
16
+ // size counts the terminator, so pass b64_orig_size() + 1.
17
+ extern unsigned long from_base64(const char *b64, uchar *str, unsigned long size);
17
18
 
18
19
  #endif /* BASE64_H */
data/ext/ox/buf.h CHANGED
@@ -57,14 +57,9 @@ inline static void buf_init(Buf buf, int fd, long initial_size) {
57
57
  buf->err = false;
58
58
  }
59
59
 
60
- inline static void buf_reset(Buf buf) {
61
- buf->head = buf->base;
62
- buf->tail = buf->head;
63
- }
64
-
65
60
  inline static void buf_cleanup(Buf buf) {
66
61
  if (buf->base != buf->head) {
67
- free(buf->head);
62
+ xfree(buf->head);
68
63
  }
69
64
  }
70
65
 
@@ -85,7 +80,9 @@ inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
85
80
  return;
86
81
  }
87
82
  buf->tail = buf->head;
88
- if (sizeof(buf->base) <= slen) {
83
+ // The buffer's capacity, not sizeof(base): init() may have taken a
84
+ // larger head.
85
+ if ((size_t)(buf->end - buf->head) <= slen) {
89
86
  if (slen != (size_t)write(buf->fd, s, slen)) {
90
87
  buf->err = true;
91
88
  return;