ox 2.14.27 → 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 +110 -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 +254 -103
- 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
data/ext/ox/cache.c
CHANGED
|
@@ -27,6 +27,23 @@
|
|
|
27
27
|
// almost the Murmur hash algorithm
|
|
28
28
|
#define M 0x5bd1e995
|
|
29
29
|
|
|
30
|
+
// Mixed into the initial state of hash_calc(). Element and attribute names come
|
|
31
|
+
// straight from the document, so without a per process seed the bucket every
|
|
32
|
+
// name lands in can be precomputed offline. Written once by ox_hash_seed_init()
|
|
33
|
+
// during Init_ox and only read afterwards, so the caches stay Ractor safe.
|
|
34
|
+
static uint64_t hash_seed = 0;
|
|
35
|
+
|
|
36
|
+
void ox_hash_seed_init(void) {
|
|
37
|
+
#ifdef HAVE_RB_HASH_START
|
|
38
|
+
// Folds in the random seed Ruby uses to defend Hash against the same attack.
|
|
39
|
+
hash_seed = (uint64_t)rb_hash_start(0);
|
|
40
|
+
#else
|
|
41
|
+
// String#hash is per process randomized too. It can be negative, so take it
|
|
42
|
+
// as signed and reinterpret rather than letting NUM2ULL reject it.
|
|
43
|
+
hash_seed = (uint64_t)(int64_t)NUM2LL(rb_funcall(rb_str_new_literal("ox"), rb_intern("hash"), 0));
|
|
44
|
+
#endif
|
|
45
|
+
}
|
|
46
|
+
|
|
30
47
|
typedef struct _slot {
|
|
31
48
|
struct _slot *next;
|
|
32
49
|
VALUE val;
|
|
@@ -68,7 +85,7 @@ const rb_data_type_t ox_cache_type = {
|
|
|
68
85
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
|
69
86
|
const uint8_t *end = key + len;
|
|
70
87
|
const uint8_t *endless = key + (len & 0xFFFFFFFC);
|
|
71
|
-
uint64_t h = (uint64_t)len;
|
|
88
|
+
uint64_t h = (uint64_t)len ^ hash_seed;
|
|
72
89
|
uint64_t k;
|
|
73
90
|
|
|
74
91
|
while (key < endless) {
|
|
@@ -100,14 +117,19 @@ static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
|
|
100
117
|
}
|
|
101
118
|
|
|
102
119
|
static void rehash(Cache c) {
|
|
103
|
-
uint64_t osize;
|
|
120
|
+
uint64_t osize = c->size;
|
|
121
|
+
Slot *slots;
|
|
104
122
|
Slot *end;
|
|
105
123
|
Slot *sp;
|
|
106
124
|
|
|
107
|
-
|
|
125
|
+
// Growing is only an optimization, and rehash() runs with the lock held, so
|
|
126
|
+
// on failure keep the current size rather than raising.
|
|
127
|
+
if (NULL == (slots = realloc((void *)c->slots, sizeof(Slot) * osize * 4))) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
108
130
|
c->size = osize * 4;
|
|
109
131
|
c->mask = c->size - 1;
|
|
110
|
-
c->slots =
|
|
132
|
+
c->slots = slots;
|
|
111
133
|
memset((Slot *)c->slots + osize, 0, sizeof(Slot) * osize * 3);
|
|
112
134
|
end = (Slot *)c->slots + osize;
|
|
113
135
|
for (sp = (Slot *)c->slots; sp < end; sp++) {
|
|
@@ -153,7 +175,10 @@ static VALUE ox_lockless_intern(Cache c, const char *key, size_t len, const char
|
|
|
153
175
|
}
|
|
154
176
|
rkey = c->form(key, len);
|
|
155
177
|
if (NULL == (b = c->reuse)) {
|
|
156
|
-
b = calloc(1, sizeof(struct _slot))
|
|
178
|
+
if (NULL == (b = calloc(1, sizeof(struct _slot)))) {
|
|
179
|
+
// Nothing modified yet and no lock held, so raising is safe.
|
|
180
|
+
rb_memerror();
|
|
181
|
+
}
|
|
157
182
|
} else {
|
|
158
183
|
c->reuse = b->next;
|
|
159
184
|
c->rcnt--;
|
|
@@ -215,8 +240,8 @@ static VALUE ox_locking_intern(Cache c, const char *key, size_t len, const char
|
|
|
215
240
|
c->rcnt--;
|
|
216
241
|
}
|
|
217
242
|
CACHE_UNLOCK(c);
|
|
218
|
-
if (NULL == b) {
|
|
219
|
-
|
|
243
|
+
if (NULL == b && NULL == (b = calloc(1, sizeof(struct _slot)))) {
|
|
244
|
+
rb_memerror(); // the lock was released above
|
|
220
245
|
}
|
|
221
246
|
rkey = c->form(key, len);
|
|
222
247
|
b->hash = h;
|
|
@@ -250,6 +275,9 @@ Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), b
|
|
|
250
275
|
Cache c = calloc(1, sizeof(struct _cache));
|
|
251
276
|
int shift = 0;
|
|
252
277
|
|
|
278
|
+
if (NULL == c) {
|
|
279
|
+
rb_memerror();
|
|
280
|
+
}
|
|
253
281
|
for (; REHASH_LIMIT < size; size /= 2, shift++) {
|
|
254
282
|
}
|
|
255
283
|
if (shift < MIN_SHIFT) {
|
|
@@ -260,9 +288,12 @@ Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), b
|
|
|
260
288
|
#else
|
|
261
289
|
c->mutex = rb_mutex_new();
|
|
262
290
|
#endif
|
|
263
|
-
c->size
|
|
264
|
-
c->mask
|
|
265
|
-
c->slots = calloc(c->size, sizeof(Slot))
|
|
291
|
+
c->size = 1 << shift;
|
|
292
|
+
c->mask = c->size - 1;
|
|
293
|
+
if (NULL == (c->slots = calloc(c->size, sizeof(Slot)))) {
|
|
294
|
+
free(c);
|
|
295
|
+
rb_memerror();
|
|
296
|
+
}
|
|
266
297
|
c->form = form;
|
|
267
298
|
c->xrate = 1; // low
|
|
268
299
|
c->mark = mark;
|
|
@@ -277,16 +308,20 @@ Cache ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), b
|
|
|
277
308
|
void ox_cache_free(void *ptr) {
|
|
278
309
|
Cache c = (Cache)ptr;
|
|
279
310
|
uint64_t i;
|
|
311
|
+
Slot next;
|
|
312
|
+
Slot s;
|
|
280
313
|
|
|
281
314
|
for (i = 0; i < c->size; i++) {
|
|
282
|
-
Slot next;
|
|
283
|
-
Slot s;
|
|
284
|
-
|
|
285
315
|
for (s = c->slots[i]; NULL != s; s = next) {
|
|
286
316
|
next = s->next;
|
|
287
317
|
free(s);
|
|
288
318
|
}
|
|
289
319
|
}
|
|
320
|
+
// ox_cache_mark retires unused slots onto the reuse list, off the buckets.
|
|
321
|
+
for (s = c->reuse; NULL != s; s = next) {
|
|
322
|
+
next = s->next;
|
|
323
|
+
free(s);
|
|
324
|
+
}
|
|
290
325
|
free((void *)c->slots);
|
|
291
326
|
free(c);
|
|
292
327
|
}
|
data/ext/ox/cache.h
CHANGED
|
@@ -13,6 +13,8 @@ struct _cache;
|
|
|
13
13
|
|
|
14
14
|
extern const rb_data_type_t ox_cache_type;
|
|
15
15
|
|
|
16
|
+
extern void ox_hash_seed_init(void);
|
|
17
|
+
|
|
16
18
|
extern struct _cache *ox_cache_create(size_t size, VALUE (*form)(const char *str, size_t len), bool mark, bool locking);
|
|
17
19
|
extern void ox_cache_free(void *ptr);
|
|
18
20
|
extern void ox_cache_mark(void *ptr);
|