oj 3.14.1 → 3.14.2
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 +4 -0
- data/ext/oj/buf.h +6 -5
- data/ext/oj/cache.c +11 -10
- data/ext/oj/cache8.c +3 -2
- data/ext/oj/circarray.c +6 -5
- data/ext/oj/compat.c +2 -1
- data/ext/oj/custom.c +3 -2
- data/ext/oj/dump.c +4 -3
- data/ext/oj/dump_object.c +3 -2
- data/ext/oj/fast.c +11 -10
- data/ext/oj/intern.c +7 -5
- data/ext/oj/mem.c +324 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +3 -2
- data/ext/oj/object.c +2 -2
- data/ext/oj/odd.c +7 -6
- data/ext/oj/oj.c +12 -5
- data/ext/oj/parse.c +14 -12
- data/ext/oj/parser.c +6 -6
- data/ext/oj/rails.c +9 -8
- data/ext/oj/reader.c +3 -2
- data/ext/oj/reader.h +3 -1
- data/ext/oj/rxclass.c +5 -4
- data/ext/oj/saj.c +6 -5
- data/ext/oj/saj2.c +6 -5
- data/ext/oj/sparse.c +5 -4
- data/ext/oj/stream_writer.c +5 -4
- data/ext/oj/string_writer.c +7 -6
- data/ext/oj/usual.c +28 -27
- data/ext/oj/val_stack.h +4 -3
- data/lib/oj/version.rb +1 -1
- data/test/foo.rb +48 -3
- data/test/perf_parser.rb +1 -0
- metadata +5 -3
data/ext/oj/mem.c
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#include <pthread.h>
|
4
|
+
#include <stdbool.h>
|
5
|
+
#include <stdint.h>
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <string.h>
|
9
|
+
|
10
|
+
#include <ruby.h>
|
11
|
+
|
12
|
+
#include "mem.h"
|
13
|
+
|
14
|
+
typedef struct _rec {
|
15
|
+
struct _rec *next;
|
16
|
+
const void *ptr;
|
17
|
+
size_t size;
|
18
|
+
const char *file;
|
19
|
+
int line;
|
20
|
+
bool ruby;
|
21
|
+
} *Rec;
|
22
|
+
|
23
|
+
typedef struct _rep {
|
24
|
+
struct _rep *next;
|
25
|
+
size_t size;
|
26
|
+
const char *file;
|
27
|
+
int line;
|
28
|
+
int cnt;
|
29
|
+
} *Rep;
|
30
|
+
|
31
|
+
#ifdef MEM_DEBUG
|
32
|
+
|
33
|
+
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
34
|
+
static Rec recs = NULL;
|
35
|
+
static const char mem_pad[] = "--- This is a memory pad and should not change until being freed. ---";
|
36
|
+
|
37
|
+
void*
|
38
|
+
oj_malloc(size_t size, const char *file, int line) {
|
39
|
+
void *ptr = malloc(size + sizeof(mem_pad));
|
40
|
+
|
41
|
+
if (NULL != ptr) {
|
42
|
+
Rec r = (Rec)malloc(sizeof(struct _rec));
|
43
|
+
|
44
|
+
if (NULL != r) {
|
45
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
46
|
+
r->ptr = ptr;
|
47
|
+
r->size = size;
|
48
|
+
r->file = file;
|
49
|
+
r->line = line;
|
50
|
+
r->ruby = false;
|
51
|
+
pthread_mutex_lock(&lock);
|
52
|
+
r->next = recs;
|
53
|
+
recs = r;
|
54
|
+
pthread_mutex_unlock(&lock);
|
55
|
+
} else {
|
56
|
+
free(ptr);
|
57
|
+
ptr = NULL;
|
58
|
+
}
|
59
|
+
}
|
60
|
+
return ptr;
|
61
|
+
}
|
62
|
+
|
63
|
+
void*
|
64
|
+
oj_realloc(void *orig, size_t size, const char *file, int line) {
|
65
|
+
void *ptr = realloc(orig, size + sizeof(mem_pad));
|
66
|
+
Rec r;
|
67
|
+
|
68
|
+
if (NULL != ptr) {
|
69
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
70
|
+
pthread_mutex_lock(&lock);
|
71
|
+
for (r = recs; NULL != r; r = r->next) {
|
72
|
+
if (orig == r->ptr) {
|
73
|
+
r->ptr = ptr;
|
74
|
+
r->size = size;
|
75
|
+
r->file = file;
|
76
|
+
r->line = line;
|
77
|
+
r->ruby = false;
|
78
|
+
break;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
pthread_mutex_unlock(&lock);
|
82
|
+
if (NULL == r) {
|
83
|
+
printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
return ptr;
|
87
|
+
}
|
88
|
+
|
89
|
+
void*
|
90
|
+
oj_calloc(size_t count, size_t size, const char *file, int line) {
|
91
|
+
void *ptr;
|
92
|
+
|
93
|
+
size *= count;
|
94
|
+
if (NULL != (ptr = malloc(size + sizeof(mem_pad)))) {
|
95
|
+
Rec r = (Rec)malloc(sizeof(struct _rec));
|
96
|
+
|
97
|
+
if (NULL != r) {
|
98
|
+
memset(ptr, 0, size);
|
99
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
100
|
+
r->ptr = ptr;
|
101
|
+
r->size = size;
|
102
|
+
r->file = file;
|
103
|
+
r->line = line;
|
104
|
+
r->ruby = false;
|
105
|
+
pthread_mutex_lock(&lock);
|
106
|
+
r->next = recs;
|
107
|
+
recs = r;
|
108
|
+
pthread_mutex_unlock(&lock);
|
109
|
+
} else {
|
110
|
+
free(ptr);
|
111
|
+
ptr = NULL;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
return ptr;
|
115
|
+
}
|
116
|
+
|
117
|
+
void*
|
118
|
+
oj_r_alloc(size_t size, const char *file, int line) {
|
119
|
+
void *ptr = ruby_xmalloc(size + sizeof(mem_pad));
|
120
|
+
|
121
|
+
if (NULL != ptr) {
|
122
|
+
Rec r = (Rec)malloc(sizeof(struct _rec));
|
123
|
+
|
124
|
+
if (NULL != r) {
|
125
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
126
|
+
r->ptr = ptr;
|
127
|
+
r->size = size;
|
128
|
+
r->file = file;
|
129
|
+
r->line = line;
|
130
|
+
r->ruby = true;
|
131
|
+
pthread_mutex_lock(&lock);
|
132
|
+
r->next = recs;
|
133
|
+
recs = r;
|
134
|
+
pthread_mutex_unlock(&lock);
|
135
|
+
} else {
|
136
|
+
free(ptr);
|
137
|
+
ptr = NULL;
|
138
|
+
}
|
139
|
+
}
|
140
|
+
return ptr;
|
141
|
+
}
|
142
|
+
|
143
|
+
void*
|
144
|
+
oj_r_realloc(void *orig, size_t size, const char *file, int line) {
|
145
|
+
void *ptr = ruby_xrealloc2(orig, 1, size + sizeof(mem_pad));
|
146
|
+
Rec r;
|
147
|
+
|
148
|
+
if (NULL != ptr) {
|
149
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
150
|
+
pthread_mutex_lock(&lock);
|
151
|
+
for (r = recs; NULL != r; r = r->next) {
|
152
|
+
if (orig == r->ptr) {
|
153
|
+
r->ptr = ptr;
|
154
|
+
r->size = size;
|
155
|
+
r->file = file;
|
156
|
+
r->line = line;
|
157
|
+
r->ruby = true;
|
158
|
+
break;
|
159
|
+
}
|
160
|
+
}
|
161
|
+
pthread_mutex_unlock(&lock);
|
162
|
+
if (NULL == r) {
|
163
|
+
printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
|
164
|
+
}
|
165
|
+
}
|
166
|
+
return ptr;
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
void
|
171
|
+
oj_freed(void *ptr, const char *file, int line, bool ruby) {
|
172
|
+
if (NULL != ptr) {
|
173
|
+
Rec r = NULL;
|
174
|
+
Rec prev = NULL;
|
175
|
+
|
176
|
+
pthread_mutex_lock(&lock);
|
177
|
+
for (r = recs; NULL != r; r = r->next) {
|
178
|
+
if (ptr == r->ptr) {
|
179
|
+
if (NULL == prev) {
|
180
|
+
recs = r->next;
|
181
|
+
} else {
|
182
|
+
prev->next = r->next;
|
183
|
+
}
|
184
|
+
break;
|
185
|
+
}
|
186
|
+
prev = r;
|
187
|
+
}
|
188
|
+
pthread_mutex_unlock(&lock);
|
189
|
+
if (NULL == r) {
|
190
|
+
printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
|
191
|
+
} else {
|
192
|
+
char *pad = (char*)r->ptr + r->size;
|
193
|
+
|
194
|
+
if (r->ruby != ruby) {
|
195
|
+
if (r->ruby) {
|
196
|
+
printf("Memory at %s:%d (%p) allocated with Ruby allocator and freed with stdlib free.\n", file, line, ptr);
|
197
|
+
} else {
|
198
|
+
printf("Memory at %s:%d (%p) allocated with stdlib allocator and freed with Ruby free.\n", file, line, ptr);
|
199
|
+
}
|
200
|
+
}
|
201
|
+
if (0 != strcmp(mem_pad, pad)) {
|
202
|
+
uint8_t *p;
|
203
|
+
uint8_t *end = (uint8_t*)pad + sizeof(mem_pad);
|
204
|
+
|
205
|
+
printf("Memory at %s:%d (%p) write outside allocated.\n", file, line, ptr);
|
206
|
+
for (p = (uint8_t*)pad; p < end; p++) {
|
207
|
+
if (0x20 < *p && *p < 0x7f) {
|
208
|
+
printf("%c ", *p);
|
209
|
+
} else {
|
210
|
+
printf("%02x ", *(uint8_t*)p);
|
211
|
+
}
|
212
|
+
}
|
213
|
+
printf("\n");
|
214
|
+
}
|
215
|
+
free(r);
|
216
|
+
}
|
217
|
+
}
|
218
|
+
}
|
219
|
+
|
220
|
+
void
|
221
|
+
oj_r_free(void *ptr, const char *file, int line) {
|
222
|
+
oj_freed(ptr, file, line, true);
|
223
|
+
xfree(ptr);
|
224
|
+
}
|
225
|
+
|
226
|
+
|
227
|
+
void
|
228
|
+
oj_free(void *ptr, const char *file, int line) {
|
229
|
+
oj_freed(ptr, file, line, false);
|
230
|
+
free(ptr);
|
231
|
+
}
|
232
|
+
|
233
|
+
char*
|
234
|
+
oj_mem_strdup(const char *str, const char *file, int line) {
|
235
|
+
size_t size = strlen(str) + 1;
|
236
|
+
char *ptr = (char*)malloc(size + sizeof(mem_pad));
|
237
|
+
|
238
|
+
if (NULL != ptr) {
|
239
|
+
Rec r = (Rec)malloc(sizeof(struct _rec));
|
240
|
+
|
241
|
+
if (NULL != r) {
|
242
|
+
strcpy(ptr, str);
|
243
|
+
strcpy(((char*)ptr) + size, mem_pad);
|
244
|
+
r->ptr = (void*)ptr;
|
245
|
+
r->size = size;
|
246
|
+
r->file = file;
|
247
|
+
r->line = line;
|
248
|
+
r->ruby = false;
|
249
|
+
pthread_mutex_lock(&lock);
|
250
|
+
r->next = recs;
|
251
|
+
recs = r;
|
252
|
+
pthread_mutex_unlock(&lock);
|
253
|
+
} else {
|
254
|
+
free(ptr);
|
255
|
+
ptr = NULL;
|
256
|
+
}
|
257
|
+
}
|
258
|
+
return ptr;
|
259
|
+
}
|
260
|
+
|
261
|
+
#endif
|
262
|
+
|
263
|
+
#ifdef MEM_DEBUG
|
264
|
+
|
265
|
+
static Rep
|
266
|
+
update_reps(Rep reps, Rec r) {
|
267
|
+
Rep rp = reps;
|
268
|
+
|
269
|
+
for (; NULL != rp; rp = rp->next) {
|
270
|
+
if (rp->line == r->line && (rp->file == r->file || 0 == strcmp(rp->file, r->file))) {
|
271
|
+
rp->size += r->size;
|
272
|
+
rp->cnt++;
|
273
|
+
break;
|
274
|
+
}
|
275
|
+
}
|
276
|
+
if (NULL == rp &&
|
277
|
+
NULL != (rp = (Rep)malloc(sizeof(struct _rep)))) {
|
278
|
+
rp->size = r->size;
|
279
|
+
rp->file = r->file;
|
280
|
+
rp->line = r->line;
|
281
|
+
rp->cnt = 1;
|
282
|
+
rp->next = reps;
|
283
|
+
reps = rp;
|
284
|
+
}
|
285
|
+
return reps;
|
286
|
+
}
|
287
|
+
|
288
|
+
static void
|
289
|
+
print_stats() {
|
290
|
+
printf("\n--- Memory Usage Report --------------------------------------------------------\n");
|
291
|
+
pthread_mutex_lock(&lock);
|
292
|
+
|
293
|
+
if (NULL == recs) {
|
294
|
+
printf("No memory leaks\n");
|
295
|
+
} else {
|
296
|
+
Rep reps = NULL;
|
297
|
+
Rep rp;
|
298
|
+
Rec r;
|
299
|
+
size_t leaked = 0;
|
300
|
+
|
301
|
+
for (r = recs; NULL != r; r = r->next) {
|
302
|
+
reps = update_reps(reps, r);
|
303
|
+
}
|
304
|
+
while (NULL != (rp = reps)) {
|
305
|
+
reps = rp->next;
|
306
|
+
printf("%16s:%3d %8lu bytes over %d occurances allocated and not freed.\n", rp->file, rp->line, rp->size, rp->cnt);
|
307
|
+
leaked += rp->size;
|
308
|
+
free(rp);
|
309
|
+
}
|
310
|
+
printf("%lu bytes leaked\n", leaked);
|
311
|
+
}
|
312
|
+
pthread_mutex_unlock(&lock);
|
313
|
+
printf("--------------------------------------------------------------------------------\n");
|
314
|
+
}
|
315
|
+
|
316
|
+
#endif
|
317
|
+
|
318
|
+
void
|
319
|
+
oj_mem_report() {
|
320
|
+
#ifdef MEM_DEBUG
|
321
|
+
rb_gc();
|
322
|
+
print_stats();
|
323
|
+
#endif
|
324
|
+
}
|
data/ext/oj/mem.h
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
// Copyright (c) 2018, Peter Ohler, All rights reserved.
|
2
|
+
|
3
|
+
#ifndef OJ_MEM_H
|
4
|
+
#define OJ_MEM_H
|
5
|
+
|
6
|
+
#include <stdio.h>
|
7
|
+
#include <stdlib.h>
|
8
|
+
#include <string.h>
|
9
|
+
|
10
|
+
#ifdef MEM_DEBUG
|
11
|
+
|
12
|
+
#define OJ_MALLOC(size) oj_malloc(size, __FILE__, __LINE__)
|
13
|
+
#define OJ_REALLOC(ptr, size) oj_realloc(ptr, size, __FILE__, __LINE__)
|
14
|
+
#define OJ_CALLOC(count, size) oj_calloc(count, size, __FILE__, __LINE__)
|
15
|
+
#define OJ_FREE(ptr) oj_free(ptr, __FILE__, __LINE__)
|
16
|
+
|
17
|
+
#define OJ_R_ALLOC(type) oj_r_alloc(sizeof(type), __FILE__, __LINE__)
|
18
|
+
#define OJ_R_ALLOC_N(type, n) (type *)oj_r_alloc(sizeof(type) * (n), __FILE__, __LINE__)
|
19
|
+
#define OJ_R_REALLOC_N(ptr, type, n) ((ptr) = (type*)oj_r_realloc(ptr, (sizeof(type) * (n)), __FILE__, __LINE__))
|
20
|
+
#define OJ_R_FREE(ptr) oj_r_free(ptr, __FILE__, __LINE__)
|
21
|
+
|
22
|
+
#define OJ_STRDUP(str) oj_mem_strdup(str, __FILE__, __LINE__)
|
23
|
+
|
24
|
+
extern void* oj_malloc(size_t size, const char *file, int line);
|
25
|
+
extern void* oj_realloc(void *ptr, size_t size, const char *file, int line);
|
26
|
+
extern void* oj_calloc(size_t count, size_t size, const char *file, int line);
|
27
|
+
extern void oj_free(void *ptr, const char *file, int line);
|
28
|
+
|
29
|
+
extern void* oj_r_alloc(size_t size, const char *file, int line);
|
30
|
+
extern void* oj_r_realloc(void *ptr, size_t size, const char *file, int line);
|
31
|
+
extern void oj_r_free(void *ptr, const char *file, int line);
|
32
|
+
|
33
|
+
extern char* oj_mem_strdup(const char *str, const char *file, int line);
|
34
|
+
|
35
|
+
#else
|
36
|
+
|
37
|
+
#define OJ_MALLOC(size) malloc(size)
|
38
|
+
#define OJ_REALLOC(ptr, size) realloc(ptr, size)
|
39
|
+
#define OJ_CALLOC(count, size) calloc(count, size)
|
40
|
+
#define OJ_FREE(ptr) free(ptr)
|
41
|
+
|
42
|
+
#define OJ_R_ALLOC(type) RB_ALLOC(type)
|
43
|
+
#define OJ_R_ALLOC_N(type, n) RB_ALLOC_N(type, n)
|
44
|
+
#define OJ_R_REALLOC_N(ptr, type, n) RB_REALLOC_N(ptr, type, n)
|
45
|
+
#define OJ_R_FREE(ptr) xfree(ptr)
|
46
|
+
|
47
|
+
#define OJ_STRDUP(str) strdup(str)
|
48
|
+
|
49
|
+
#endif
|
50
|
+
|
51
|
+
extern void oj_mem_report();
|
52
|
+
|
53
|
+
#endif /* OJ_MEM_H */
|
data/ext/oj/mimic_json.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
2
|
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
3
|
|
4
|
+
#include "mem.h"
|
4
5
|
#include "dump.h"
|
5
6
|
#include "encode.h"
|
6
7
|
#include "oj.h"
|
@@ -664,7 +665,7 @@ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
|
|
664
665
|
|
665
666
|
if (NULL != oj_default_options.create_id) {
|
666
667
|
if (oj_json_class != oj_default_options.create_id) {
|
667
|
-
|
668
|
+
OJ_R_FREE((char *)oj_default_options.create_id);
|
668
669
|
}
|
669
670
|
oj_default_options.create_id = NULL;
|
670
671
|
oj_default_options.create_id_len = 0;
|
@@ -672,7 +673,7 @@ static VALUE mimic_set_create_id(VALUE self, VALUE id) {
|
|
672
673
|
if (Qnil != id) {
|
673
674
|
size_t len = RSTRING_LEN(id) + 1;
|
674
675
|
|
675
|
-
oj_default_options.create_id =
|
676
|
+
oj_default_options.create_id = OJ_R_ALLOC_N(char, len);
|
676
677
|
strcpy((char *)oj_default_options.create_id, StringValuePtr(id));
|
677
678
|
oj_default_options.create_id_len = len - 1;
|
678
679
|
}
|
data/ext/oj/object.c
CHANGED
@@ -352,7 +352,7 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
352
352
|
}
|
353
353
|
return 1;
|
354
354
|
} else if (3 <= klen && '#' == key[1]) {
|
355
|
-
volatile VALUE *a;
|
355
|
+
volatile const VALUE *a;
|
356
356
|
|
357
357
|
if (2 != len) {
|
358
358
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
@@ -546,7 +546,7 @@ WHICH_TYPE:
|
|
546
546
|
} else {
|
547
547
|
if (3 <= klen && '^' == *key && '#' == key[1] && T_ARRAY == rb_type(value)) {
|
548
548
|
long len = RARRAY_LEN(value);
|
549
|
-
volatile VALUE *a = RARRAY_CONST_PTR(value);
|
549
|
+
volatile const VALUE *a = RARRAY_CONST_PTR(value);
|
550
550
|
|
551
551
|
if (2 != len) {
|
552
552
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid hash pair");
|
data/ext/oj/odd.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
// Copyright (c) 2011 Peter Ohler. All rights reserved.
|
2
2
|
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
3
|
|
4
|
+
#include "mem.h"
|
4
5
|
#include "odd.h"
|
5
6
|
|
6
7
|
#include <string.h>
|
@@ -68,7 +69,7 @@ void print_all_odds(const char *label) {
|
|
68
69
|
}
|
69
70
|
|
70
71
|
static Odd odd_create(void) {
|
71
|
-
Odd odd =
|
72
|
+
Odd odd = OJ_R_ALLOC(struct _odd);
|
72
73
|
|
73
74
|
memset(odd, 0, sizeof(struct _odd));
|
74
75
|
odd->next = odds;
|
@@ -172,7 +173,7 @@ Odd oj_get_oddc(const char *classname, size_t len) {
|
|
172
173
|
}
|
173
174
|
|
174
175
|
OddArgs oj_odd_alloc_args(Odd odd) {
|
175
|
-
OddArgs oa =
|
176
|
+
OddArgs oa = OJ_R_ALLOC_N(struct _oddArgs, 1);
|
176
177
|
VALUE *a;
|
177
178
|
int i;
|
178
179
|
|
@@ -184,7 +185,7 @@ OddArgs oj_odd_alloc_args(Odd odd) {
|
|
184
185
|
}
|
185
186
|
|
186
187
|
void oj_odd_free(OddArgs args) {
|
187
|
-
|
188
|
+
OJ_R_FREE(args);
|
188
189
|
}
|
189
190
|
|
190
191
|
int oj_odd_set_arg(OddArgs args, const char *key, size_t klen, VALUE value) {
|
@@ -210,7 +211,7 @@ void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt,
|
|
210
211
|
odd = odd_create();
|
211
212
|
odd->clas = clas;
|
212
213
|
rb_gc_register_mark_object(odd->clas);
|
213
|
-
if (NULL == (odd->classname =
|
214
|
+
if (NULL == (odd->classname = OJ_STRDUP(rb_class2name(clas)))) {
|
214
215
|
rb_raise(rb_eNoMemError, "for class name.");
|
215
216
|
}
|
216
217
|
odd->clen = strlen(odd->classname);
|
@@ -224,13 +225,13 @@ void oj_reg_odd(VALUE clas, VALUE create_object, VALUE create_method, int mcnt,
|
|
224
225
|
*fp = 0;
|
225
226
|
switch (rb_type(*members)) {
|
226
227
|
case T_STRING:
|
227
|
-
if (NULL == (*np =
|
228
|
+
if (NULL == (*np = OJ_STRDUP(RSTRING_PTR(*members)))) {
|
228
229
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
229
230
|
}
|
230
231
|
break;
|
231
232
|
case T_SYMBOL:
|
232
233
|
// The symbol can move and invalidate the name so make a copy.
|
233
|
-
if (NULL == (*np =
|
234
|
+
if (NULL == (*np = OJ_STRDUP(rb_id2name(SYM2ID(*members))))) {
|
234
235
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
235
236
|
}
|
236
237
|
break;
|
data/ext/oj/oj.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <sys/types.h>
|
12
12
|
#include <unistd.h>
|
13
13
|
|
14
|
+
#include "mem.h"
|
14
15
|
#include "dump.h"
|
15
16
|
#include "encode.h"
|
16
17
|
#include "intern.h"
|
@@ -782,7 +783,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
782
783
|
} else if (create_id_sym == k) {
|
783
784
|
if (Qnil == v) {
|
784
785
|
if (oj_json_class != oj_default_options.create_id && NULL != copts->create_id) {
|
785
|
-
|
786
|
+
OJ_R_FREE((char *)oj_default_options.create_id);
|
786
787
|
}
|
787
788
|
copts->create_id = NULL;
|
788
789
|
copts->create_id_len = 0;
|
@@ -791,7 +792,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
791
792
|
|
792
793
|
len = RSTRING_LEN(v);
|
793
794
|
if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
|
794
|
-
copts->create_id =
|
795
|
+
copts->create_id = OJ_R_ALLOC_N(char, len + 1);
|
795
796
|
strcpy((char *)copts->create_id, str);
|
796
797
|
copts->create_id_len = len;
|
797
798
|
}
|
@@ -911,7 +912,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
911
912
|
copts->array_class = v;
|
912
913
|
}
|
913
914
|
} else if (ignore_sym == k) {
|
914
|
-
|
915
|
+
OJ_R_FREE(copts->ignore);
|
915
916
|
copts->ignore = NULL;
|
916
917
|
if (Qnil != v) {
|
917
918
|
int cnt;
|
@@ -921,7 +922,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
921
922
|
if (0 < cnt) {
|
922
923
|
int i;
|
923
924
|
|
924
|
-
copts->ignore =
|
925
|
+
copts->ignore = OJ_R_ALLOC_N(VALUE, cnt + 1);
|
925
926
|
for (i = 0; i < cnt; i++) {
|
926
927
|
copts->ignore[i] = RARRAY_AREF(v, i);
|
927
928
|
}
|
@@ -1159,7 +1160,7 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
|
|
1159
1160
|
WCHAR *wide_path;
|
1160
1161
|
wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
|
1161
1162
|
fd = rb_w32_wopen(wide_path, O_RDONLY);
|
1162
|
-
|
1163
|
+
OJ_FREE(wide_path);
|
1163
1164
|
}
|
1164
1165
|
#else
|
1165
1166
|
fd = open(path, O_RDONLY);
|
@@ -1724,6 +1725,10 @@ debug_odd(VALUE self, VALUE label) {
|
|
1724
1725
|
return Qnil;
|
1725
1726
|
}
|
1726
1727
|
|
1728
|
+
static VALUE mem_report(VALUE self) {
|
1729
|
+
oj_mem_report();
|
1730
|
+
return Qnil;
|
1731
|
+
}
|
1727
1732
|
|
1728
1733
|
/* Document-module: Oj
|
1729
1734
|
*
|
@@ -1812,6 +1817,8 @@ void Init_oj(void) {
|
|
1812
1817
|
|
1813
1818
|
rb_define_module_function(Oj, "optimize_rails", oj_optimize_rails, 0);
|
1814
1819
|
|
1820
|
+
rb_define_module_function(Oj, "mem_report", mem_report, 0);
|
1821
|
+
|
1815
1822
|
oj_add_value_id = rb_intern("add_value");
|
1816
1823
|
oj_array_append_id = rb_intern("array_append");
|
1817
1824
|
oj_array_end_id = rb_intern("array_end");
|
data/ext/oj/parse.c
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
#include <string.h>
|
11
11
|
#include <unistd.h>
|
12
12
|
|
13
|
+
#include "mem.h"
|
13
14
|
#include "buf.h"
|
14
15
|
#include "encode.h"
|
15
16
|
#include "oj.h"
|
@@ -87,7 +88,7 @@ static void add_value(ParseInfo pi, VALUE rval) {
|
|
87
88
|
pi->hash_set_value(pi, parent, rval);
|
88
89
|
if (0 != parent->key && 0 < parent->klen &&
|
89
90
|
(parent->key < pi->json || pi->cur < parent->key)) {
|
90
|
-
|
91
|
+
OJ_R_FREE((char *)parent->key);
|
91
92
|
parent->key = 0;
|
92
93
|
}
|
93
94
|
parent->next = NEXT_HASH_COMMA;
|
@@ -236,7 +237,8 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
236
237
|
|
237
238
|
for (s = pi->cur; '"' != *s;) {
|
238
239
|
const char *scanned = scan_func(s, pi->end);
|
239
|
-
if (scanned >= pi->end || '\0' == *
|
240
|
+
if (scanned >= pi->end || '\0' == *scanned) {
|
241
|
+
//if (scanned >= pi->end) {
|
240
242
|
oj_set_error_at(pi,
|
241
243
|
oj_parse_error_class,
|
242
244
|
__FILE__,
|
@@ -333,7 +335,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
333
335
|
case NEXT_HASH_KEY:
|
334
336
|
if (Qundef == (parent->key_val = pi->hash_key(pi, buf.head, buf_len(&buf)))) {
|
335
337
|
parent->klen = buf_len(&buf);
|
336
|
-
parent->key =
|
338
|
+
parent->key = OJ_MALLOC(parent->klen + 1);
|
337
339
|
memcpy((char *)parent->key, buf.head, parent->klen);
|
338
340
|
*(char *)(parent->key + parent->klen) = '\0';
|
339
341
|
} else {
|
@@ -347,7 +349,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
347
349
|
pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), start);
|
348
350
|
if (0 != parent->key && 0 < parent->klen &&
|
349
351
|
(parent->key < pi->json || pi->cur < parent->key)) {
|
350
|
-
|
352
|
+
OJ_R_FREE((char *)parent->key);
|
351
353
|
parent->key = 0;
|
352
354
|
}
|
353
355
|
parent->next = NEXT_HASH_COMMA;
|
@@ -417,7 +419,7 @@ static void read_str(ParseInfo pi) {
|
|
417
419
|
pi->hash_set_cstr(pi, parent, str, pi->cur - str, str);
|
418
420
|
if (0 != parent->key && 0 < parent->klen &&
|
419
421
|
(parent->key < pi->json || pi->cur < parent->key)) {
|
420
|
-
|
422
|
+
OJ_R_FREE((char *)parent->key);
|
421
423
|
parent->key = 0;
|
422
424
|
}
|
423
425
|
parent->next = NEXT_HASH_COMMA;
|
@@ -616,7 +618,7 @@ static void read_num(ParseInfo pi) {
|
|
616
618
|
pi->hash_set_num(pi, parent, &ni);
|
617
619
|
if (0 != parent->key && 0 < parent->klen &&
|
618
620
|
(parent->key < pi->json || pi->cur < parent->key)) {
|
619
|
-
|
621
|
+
OJ_R_FREE((char *)parent->key);
|
620
622
|
parent->key = 0;
|
621
623
|
}
|
622
624
|
parent->next = NEXT_HASH_COMMA;
|
@@ -870,12 +872,12 @@ oj_num_as_value(NumInfo ni) {
|
|
870
872
|
buf[ni->len] = '\0';
|
871
873
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
872
874
|
} else {
|
873
|
-
char *buf =
|
875
|
+
char *buf = OJ_R_ALLOC_N(char, ni->len + 1);
|
874
876
|
|
875
877
|
memcpy(buf, ni->str, ni->len);
|
876
878
|
buf[ni->len] = '\0';
|
877
879
|
rnum = rb_cstr_to_inum(buf, 10, 0);
|
878
|
-
|
880
|
+
OJ_R_FREE(buf);
|
879
881
|
}
|
880
882
|
} else {
|
881
883
|
if (ni->neg) {
|
@@ -1076,12 +1078,12 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1076
1078
|
size_t len = lseek(fd, 0, SEEK_END);
|
1077
1079
|
|
1078
1080
|
lseek(fd, 0, SEEK_SET);
|
1079
|
-
buf =
|
1081
|
+
buf = OJ_R_ALLOC_N(char, len + 1);
|
1080
1082
|
pi->json = buf;
|
1081
1083
|
pi->end = buf + len;
|
1082
1084
|
if (0 >= (cnt = read(fd, (char *)pi->json, len)) || cnt != (ssize_t)len) {
|
1083
1085
|
if (0 != buf) {
|
1084
|
-
|
1086
|
+
OJ_R_FREE(buf);
|
1085
1087
|
}
|
1086
1088
|
rb_raise(rb_eIOError, "failed to read from IO Object.");
|
1087
1089
|
}
|
@@ -1163,9 +1165,9 @@ CLEANUP:
|
|
1163
1165
|
oj_circ_array_free(pi->circ_array);
|
1164
1166
|
}
|
1165
1167
|
if (0 != buf) {
|
1166
|
-
|
1168
|
+
OJ_R_FREE(buf);
|
1167
1169
|
} else if (free_json) {
|
1168
|
-
|
1170
|
+
OJ_R_FREE(json);
|
1169
1171
|
}
|
1170
1172
|
stack_cleanup(&pi->stack);
|
1171
1173
|
if (pi->str_rx.head != oj_default_options.str_rx.head) {
|