ox 2.14.26 → 2.14.27
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 +14 -0
- data/ext/ox/base64.c +1 -1
- data/ext/ox/ox.c +3 -1
- data/ext/ox/parse.c +12 -5
- data/lib/ox/version.rb +1 -1
- metadata +2 -3
- data/ext/ox/foo.h +0 -204
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b981c5e93cbbe907c8beb655007ebd2d3bfd740da911372ce82ea329e85773f0
|
|
4
|
+
data.tar.gz: 98935b178f268fad229368d02b2efd14529b4144aebae15b557aed80d20a5aac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aaa1d3f2183519ef26fd82b80f1bae7bef61216e8404ae03fcc0ad7c9b8e450b2acb423cb7f113be08fa3cab8ba448cf25425e7cc12e138a63e04c93642e2523
|
|
7
|
+
data.tar.gz: b0b0e20339a346d17a3a29b57e8c1d722b5999d346d775c6f587400aa8affa30e63186a5a6109dd59091fd13ecc172ef93d69e8168bc65a2aa70bd66e76f58ec
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All changes to the Ox gem are documented here. Releases follow semantic versioning.
|
|
4
4
|
|
|
5
|
+
## [2.14.27] - 2026-06-18
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed stack overflow issue in the parser that occurred when reading
|
|
10
|
+
special character sequences.
|
|
11
|
+
|
|
12
|
+
- Set a limit of 1000 as the maximum nesting depth of elements to
|
|
13
|
+
avoid stack exhaustion.
|
|
14
|
+
|
|
15
|
+
- Added a note on the symbolize_keys option indicating it should not
|
|
16
|
+
be used on unregulated input where the symbol table could grow
|
|
17
|
+
indefinitely.
|
|
18
|
+
|
|
5
19
|
## [2.14.26] - 2026-05-09
|
|
6
20
|
|
|
7
21
|
### Fixed
|
data/ext/ox/base64.c
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
static char digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
12
12
|
|
|
13
13
|
/* invalid or terminating characters are set to 'X' or \x58 */
|
|
14
|
-
static uchar s_digits[
|
|
14
|
+
static uchar s_digits[257] = "\
|
|
15
15
|
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
|
16
16
|
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\
|
|
17
17
|
\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x58\x3E\x58\x58\x58\x3F\
|
data/ext/ox/ox.c
CHANGED
|
@@ -274,7 +274,9 @@ static VALUE hints_to_overlay(Hints hints) {
|
|
|
274
274
|
* - _:xsd_date_ [true|false|nil] use XSD date format instead of decimal format
|
|
275
275
|
* - _:mode_ [:object|:generic|:limited|:hash|:hash_no_attrs|nil] load method to use for XML
|
|
276
276
|
* - _:effort_ [:strict|:tolerant|:auto_define] set the tolerance level for loading
|
|
277
|
-
* - _:symbolize_keys_ [true|false|nil] symbolize element attribute keys or leave as Strings
|
|
277
|
+
* - _:symbolize_keys_ [true|false|nil] symbolize element attribute keys or leave as Strings.
|
|
278
|
+
* Note that symbolized keys are more efficient but for uncontrolled input it can lead to unlimited
|
|
279
|
+
* growth of the symbol (intern) table.
|
|
278
280
|
* - _:element_key_mod_ [Proc|nil] converts element keys on parse if not nil
|
|
279
281
|
* - _:attr_key_mod_ [Proc|nil] converts attribute keys on parse if not nil
|
|
280
282
|
* - _:skip_ [:skip_none|:skip_return|:skip_white|:skip_off] determines how to handle white space in text
|
data/ext/ox/parse.c
CHANGED
|
@@ -18,11 +18,13 @@
|
|
|
18
18
|
#include "ruby.h"
|
|
19
19
|
#include "special.h"
|
|
20
20
|
|
|
21
|
+
#define MAX_ELEMENT_DEPTH 1000
|
|
22
|
+
|
|
21
23
|
static void mark_pi_cb(void *ptr);
|
|
22
24
|
static void read_instruction(PInfo pi);
|
|
23
25
|
static void read_doctype(PInfo pi);
|
|
24
26
|
static void read_comment(PInfo pi);
|
|
25
|
-
static char *read_element(PInfo pi);
|
|
27
|
+
static char *read_element(PInfo pi, int depth);
|
|
26
28
|
static void read_text(PInfo pi);
|
|
27
29
|
/*static void read_reduced_text(PInfo pi); */
|
|
28
30
|
static void read_cdata(PInfo pi);
|
|
@@ -216,7 +218,7 @@ ox_parse(char *xml, size_t len, ParseCallbacks pcb, char **endp, Options options
|
|
|
216
218
|
helper_stack_cleanup(&pi.helpers);
|
|
217
219
|
return Qnil;
|
|
218
220
|
default:
|
|
219
|
-
read_element(&pi);
|
|
221
|
+
read_element(&pi, 0);
|
|
220
222
|
body_read = 1;
|
|
221
223
|
break;
|
|
222
224
|
}
|
|
@@ -452,7 +454,7 @@ static void read_comment(PInfo pi) {
|
|
|
452
454
|
|
|
453
455
|
// Entered after the '<' and the first character after that. Returns stat
|
|
454
456
|
// code.
|
|
455
|
-
static char *read_element(PInfo pi) {
|
|
457
|
+
static char *read_element(PInfo pi, int depth) {
|
|
456
458
|
struct _attrStack attrs;
|
|
457
459
|
const char *attr_name;
|
|
458
460
|
const char *attr_value;
|
|
@@ -464,6 +466,10 @@ static char *read_element(PInfo pi) {
|
|
|
464
466
|
int hasChildren = 0;
|
|
465
467
|
int done = 0;
|
|
466
468
|
|
|
469
|
+
if (MAX_ELEMENT_DEPTH < depth) {
|
|
470
|
+
set_error(&pi->err, "element nested too deeply, limit is 1000", pi->str, pi->s);
|
|
471
|
+
return 0;
|
|
472
|
+
}
|
|
467
473
|
attr_stack_init(&attrs);
|
|
468
474
|
if (0 == (ename = read_name_token(pi))) {
|
|
469
475
|
return 0;
|
|
@@ -684,7 +690,7 @@ static char *read_element(PInfo pi) {
|
|
|
684
690
|
first = 0;
|
|
685
691
|
/* a child element */
|
|
686
692
|
// Child closed with mismatched name.
|
|
687
|
-
if (0 != (name = read_element(pi))) {
|
|
693
|
+
if (0 != (name = read_element(pi, depth + 1))) {
|
|
688
694
|
attr_stack_cleanup(&attrs);
|
|
689
695
|
|
|
690
696
|
if (0 ==
|
|
@@ -1056,7 +1062,8 @@ static char *read_coded_chars(PInfo pi, char *text) {
|
|
|
1056
1062
|
break;
|
|
1057
1063
|
}
|
|
1058
1064
|
}
|
|
1059
|
-
if (b
|
|
1065
|
+
if (b >= end) {
|
|
1066
|
+
// No terminating ; found in the first 31 bytes after an &.
|
|
1060
1067
|
*text++ = '&';
|
|
1061
1068
|
} else if ('#' == *buf) {
|
|
1062
1069
|
uint64_t u = 0;
|
data/lib/ox/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.14.
|
|
4
|
+
version: 2.14.27
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter Ohler
|
|
@@ -51,7 +51,6 @@ files:
|
|
|
51
51
|
- ext/ox/err.c
|
|
52
52
|
- ext/ox/err.h
|
|
53
53
|
- ext/ox/extconf.rb
|
|
54
|
-
- ext/ox/foo.h
|
|
55
54
|
- ext/ox/gen_load.c
|
|
56
55
|
- ext/ox/hash_load.c
|
|
57
56
|
- ext/ox/helper.h
|
|
@@ -123,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
123
122
|
- !ruby/object:Gem::Version
|
|
124
123
|
version: '0'
|
|
125
124
|
requirements: []
|
|
126
|
-
rubygems_version: 4.0.
|
|
125
|
+
rubygems_version: 4.0.6
|
|
127
126
|
specification_version: 4
|
|
128
127
|
summary: A fast XML parser and object serializer.
|
|
129
128
|
test_files: []
|
data/ext/ox/foo.h
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
/* sax_buf.h
|
|
2
|
-
* Copyright (c) 2011, Peter Ohler
|
|
3
|
-
* All rights reserved.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
#ifndef OX_SAX_BUF_H
|
|
7
|
-
#define OX_SAX_BUF_H
|
|
8
|
-
|
|
9
|
-
#include <stdio.h>
|
|
10
|
-
|
|
11
|
-
typedef struct _buf {
|
|
12
|
-
char base[0x00001000];
|
|
13
|
-
char *head;
|
|
14
|
-
char *end;
|
|
15
|
-
char *tail;
|
|
16
|
-
char *read_end; /* one past last character read */
|
|
17
|
-
char *pro; /* protection start, buffer can not slide past this point */
|
|
18
|
-
char *str; /* start of current string being read */
|
|
19
|
-
off_t pos;
|
|
20
|
-
off_t line;
|
|
21
|
-
off_t col;
|
|
22
|
-
off_t pro_pos;
|
|
23
|
-
off_t pro_line;
|
|
24
|
-
off_t pro_col;
|
|
25
|
-
int (*read_func)(struct _buf *buf);
|
|
26
|
-
union {
|
|
27
|
-
int fd;
|
|
28
|
-
VALUE io;
|
|
29
|
-
const char *str;
|
|
30
|
-
} in;
|
|
31
|
-
struct _saxDrive *dr;
|
|
32
|
-
} *Buf;
|
|
33
|
-
|
|
34
|
-
typedef struct _checkPt {
|
|
35
|
-
off_t pro_dif;
|
|
36
|
-
off_t pos;
|
|
37
|
-
off_t line;
|
|
38
|
-
off_t col;
|
|
39
|
-
char c;
|
|
40
|
-
} *CheckPt;
|
|
41
|
-
|
|
42
|
-
#define CHECK_PT_INIT {-1, 0, 0, 0, '\0'}
|
|
43
|
-
|
|
44
|
-
extern void ox_sax_buf_init(Buf buf, VALUE io);
|
|
45
|
-
extern int ox_sax_buf_read(Buf buf);
|
|
46
|
-
|
|
47
|
-
static inline char buf_get(Buf buf) {
|
|
48
|
-
// printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n", buf->tail, buf->tail -
|
|
49
|
-
// buf->head, buf->head, buf->read_end - buf->tail);
|
|
50
|
-
if (buf->read_end <= buf->tail) {
|
|
51
|
-
if (0 != ox_sax_buf_read(buf)) {
|
|
52
|
-
return '\0';
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if ('\n' == *buf->tail) {
|
|
56
|
-
buf->line++;
|
|
57
|
-
buf->col = 0;
|
|
58
|
-
} else {
|
|
59
|
-
buf->col++;
|
|
60
|
-
}
|
|
61
|
-
buf->pos++;
|
|
62
|
-
|
|
63
|
-
return *buf->tail++;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
static inline void buf_backup(Buf buf) {
|
|
67
|
-
buf->tail--;
|
|
68
|
-
buf->col--;
|
|
69
|
-
buf->pos--;
|
|
70
|
-
if (0 >= buf->col) {
|
|
71
|
-
buf->line--;
|
|
72
|
-
// allow col to be negative since we never backup twice in a row
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
static inline void buf_protect(Buf buf) {
|
|
77
|
-
buf->pro = buf->tail;
|
|
78
|
-
buf->str = buf->tail; // can't have str before pro
|
|
79
|
-
buf->pro_pos = buf->pos;
|
|
80
|
-
buf->pro_line = buf->line;
|
|
81
|
-
buf->pro_col = buf->col;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
static inline void buf_reset(Buf buf) {
|
|
85
|
-
buf->tail = buf->pro;
|
|
86
|
-
buf->pos = buf->pro_pos;
|
|
87
|
-
buf->line = buf->pro_line;
|
|
88
|
-
buf->col = buf->pro_col;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/* Starts by reading a character so it is safe to use with an empty or
|
|
92
|
-
* compacted buffer.
|
|
93
|
-
*/
|
|
94
|
-
static inline char buf_next_non_white(Buf buf) {
|
|
95
|
-
char c;
|
|
96
|
-
|
|
97
|
-
while ('\0' != (c = buf_get(buf))) {
|
|
98
|
-
switch (c) {
|
|
99
|
-
case ' ':
|
|
100
|
-
case '\t':
|
|
101
|
-
case '\f':
|
|
102
|
-
case '\n':
|
|
103
|
-
case '\r': break;
|
|
104
|
-
default: return c;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return '\0';
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/* Starts by reading a character so it is safe to use with an empty or
|
|
111
|
-
* compacted buffer.
|
|
112
|
-
*/
|
|
113
|
-
static inline char buf_next_white(Buf buf) {
|
|
114
|
-
char c;
|
|
115
|
-
|
|
116
|
-
while ('\0' != (c = buf_get(buf))) {
|
|
117
|
-
switch (c) {
|
|
118
|
-
case ' ':
|
|
119
|
-
case '\t':
|
|
120
|
-
case '\f':
|
|
121
|
-
case '\n':
|
|
122
|
-
case '\r':
|
|
123
|
-
case '\0': return c;
|
|
124
|
-
default: break;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return '\0';
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
static inline void buf_cleanup(Buf buf) {
|
|
131
|
-
if (buf->base != buf->head && 0 != buf->head) {
|
|
132
|
-
xfree(buf->head);
|
|
133
|
-
buf->head = 0;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
static inline int is_white(char c) {
|
|
138
|
-
switch (c) {
|
|
139
|
-
case ' ':
|
|
140
|
-
case '\t':
|
|
141
|
-
case '\f':
|
|
142
|
-
case '\n':
|
|
143
|
-
case '\r': return 1;
|
|
144
|
-
default: break;
|
|
145
|
-
}
|
|
146
|
-
return 0;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
static inline void buf_checkpoint(Buf buf, CheckPt cp) {
|
|
150
|
-
cp->pro_dif = (int)(buf->tail - buf->pro);
|
|
151
|
-
cp->pos = buf->pos;
|
|
152
|
-
cp->line = buf->line;
|
|
153
|
-
cp->col = buf->col;
|
|
154
|
-
cp->c = *(buf->tail - 1);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
static inline int buf_checkset(CheckPt cp) {
|
|
158
|
-
return (0 <= cp->pro_dif);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
static inline char buf_checkback(Buf buf, CheckPt cp) {
|
|
162
|
-
buf->tail = buf->pro + cp->pro_dif;
|
|
163
|
-
buf->pos = cp->pos;
|
|
164
|
-
buf->line = cp->line;
|
|
165
|
-
buf->col = cp->col;
|
|
166
|
-
return cp->c;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
static inline void buf_collapse_return(char *str) {
|
|
170
|
-
char *s = str;
|
|
171
|
-
char *back = str;
|
|
172
|
-
|
|
173
|
-
for (; '\0' != *s; s++) {
|
|
174
|
-
if (back != str && '\n' == *s && '\r' == *(back - 1)) {
|
|
175
|
-
*(back - 1) = '\n';
|
|
176
|
-
} else {
|
|
177
|
-
*back++ = *s;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
*back = '\0';
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
static inline void buf_collapse_white(char *str) {
|
|
184
|
-
char *s = str;
|
|
185
|
-
char *back = str;
|
|
186
|
-
|
|
187
|
-
for (; '\0' != *s; s++) {
|
|
188
|
-
switch (*s) {
|
|
189
|
-
case ' ':
|
|
190
|
-
case '\t':
|
|
191
|
-
case '\f':
|
|
192
|
-
case '\n':
|
|
193
|
-
case '\r':
|
|
194
|
-
if (back == str || ' ' != *(back - 1)) {
|
|
195
|
-
*back++ = ' ';
|
|
196
|
-
}
|
|
197
|
-
break;
|
|
198
|
-
default: *back++ = *s; break;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
*back = '\0';
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
#endif /* OX_SAX_BUF_H */
|