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 +4 -4
- data/CHANGELOG.md +103 -0
- data/ext/ox/base64.c +24 -17
- data/ext/ox/base64.h +2 -1
- data/ext/ox/buf.h +4 -7
- data/ext/ox/builder.c +277 -122
- data/ext/ox/cache.c +48 -13
- data/ext/ox/cache.h +2 -0
- data/ext/ox/dump.c +374 -221
- data/ext/ox/extconf.rb +3 -0
- data/ext/ox/gen_load.c +10 -8
- data/ext/ox/hash_load.c +7 -2
- data/ext/ox/helper.h +10 -6
- data/ext/ox/intern.c +6 -1
- data/ext/ox/obj_load.c +207 -47
- data/ext/ox/ox.c +179 -38
- data/ext/ox/ox.h +11 -1
- data/ext/ox/parse.c +249 -106
- data/ext/ox/sax.c +22 -18
- data/ext/ox/sax_as.c +42 -10
- data/ext/ox/sax_buf.c +23 -8
- data/ext/ox/sax_stack.h +13 -0
- data/ext/ox/time_conv.h +62 -0
- data/ext/ox/xml_check.h +58 -0
- data/ext/ox/xml_str.h +247 -0
- data/lib/ox/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8ebfb30efd11a67a36973ca7fd8ada6eb2d193a0667882ccb78498cdb1362f32
|
|
4
|
+
data.tar.gz: a1a41cceb0750adc25b6ee9dff8d7b4c2921e6335ba49e1a2daac3de39f98d16
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
69
|
+
unsigned long cnt;
|
|
67
70
|
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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;
|