oj 3.14.1 → 3.14.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/README.md +0 -1
  4. data/ext/oj/buf.h +7 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +7 -5
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +2 -2
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +7 -14
  12. data/ext/oj/custom.c +3 -2
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +18 -17
  15. data/ext/oj/dump_compat.c +551 -576
  16. data/ext/oj/dump_leaf.c +3 -5
  17. data/ext/oj/dump_object.c +37 -37
  18. data/ext/oj/dump_strict.c +2 -4
  19. data/ext/oj/encoder.c +1 -1
  20. data/ext/oj/err.c +2 -13
  21. data/ext/oj/err.h +9 -12
  22. data/ext/oj/extconf.rb +1 -1
  23. data/ext/oj/fast.c +33 -46
  24. data/ext/oj/intern.c +44 -46
  25. data/ext/oj/intern.h +3 -7
  26. data/ext/oj/mem.c +318 -0
  27. data/ext/oj/mem.h +53 -0
  28. data/ext/oj/mimic_json.c +20 -25
  29. data/ext/oj/object.c +7 -7
  30. data/ext/oj/odd.c +8 -6
  31. data/ext/oj/odd.h +4 -4
  32. data/ext/oj/oj.c +71 -85
  33. data/ext/oj/oj.h +53 -54
  34. data/ext/oj/parse.c +67 -128
  35. data/ext/oj/parse.h +5 -10
  36. data/ext/oj/parser.c +13 -14
  37. data/ext/oj/parser.h +7 -8
  38. data/ext/oj/rails.c +36 -66
  39. data/ext/oj/reader.c +8 -11
  40. data/ext/oj/reader.h +4 -2
  41. data/ext/oj/resolve.c +3 -4
  42. data/ext/oj/rxclass.c +6 -5
  43. data/ext/oj/rxclass.h +1 -1
  44. data/ext/oj/saj.c +9 -8
  45. data/ext/oj/saj2.c +36 -52
  46. data/ext/oj/saj2.h +1 -1
  47. data/ext/oj/scp.c +3 -14
  48. data/ext/oj/sparse.c +22 -70
  49. data/ext/oj/stream_writer.c +9 -21
  50. data/ext/oj/strict.c +7 -13
  51. data/ext/oj/string_writer.c +11 -18
  52. data/ext/oj/trace.h +27 -16
  53. data/ext/oj/usual.c +89 -87
  54. data/ext/oj/usual.h +6 -6
  55. data/ext/oj/util.h +1 -1
  56. data/ext/oj/val_stack.h +8 -7
  57. data/ext/oj/wab.c +7 -9
  58. data/lib/oj/active_support_helper.rb +0 -1
  59. data/lib/oj/bag.rb +7 -1
  60. data/lib/oj/easy_hash.rb +4 -5
  61. data/lib/oj/error.rb +0 -1
  62. data/lib/oj/json.rb +4 -2
  63. data/lib/oj/mimic.rb +4 -2
  64. data/lib/oj/state.rb +8 -5
  65. data/lib/oj/version.rb +1 -2
  66. data/lib/oj.rb +0 -1
  67. data/test/_test_active.rb +0 -1
  68. data/test/_test_active_mimic.rb +0 -1
  69. data/test/_test_mimic_rails.rb +0 -1
  70. data/test/activerecord/result_test.rb +5 -6
  71. data/test/bar.rb +3 -3
  72. data/test/files.rb +1 -1
  73. data/test/foo.rb +5 -3
  74. data/test/helper.rb +1 -4
  75. data/test/isolated/shared.rb +3 -2
  76. data/test/json_gem/json_addition_test.rb +2 -2
  77. data/test/json_gem/json_common_interface_test.rb +4 -4
  78. data/test/json_gem/json_encoding_test.rb +0 -0
  79. data/test/json_gem/json_ext_parser_test.rb +1 -0
  80. data/test/json_gem/json_fixtures_test.rb +3 -2
  81. data/test/json_gem/json_generator_test.rb +43 -32
  82. data/test/json_gem/json_generic_object_test.rb +11 -11
  83. data/test/json_gem/json_parser_test.rb +46 -46
  84. data/test/json_gem/json_string_matching_test.rb +9 -9
  85. data/test/mem.rb +7 -7
  86. data/test/perf.rb +2 -2
  87. data/test/perf_compat.rb +1 -1
  88. data/test/perf_fast.rb +1 -1
  89. data/test/perf_file.rb +2 -2
  90. data/test/perf_object.rb +1 -2
  91. data/test/perf_once.rb +4 -4
  92. data/test/perf_parser.rb +2 -2
  93. data/test/perf_saj.rb +1 -2
  94. data/test/perf_scp.rb +1 -1
  95. data/test/perf_simple.rb +3 -3
  96. data/test/perf_strict.rb +1 -1
  97. data/test/perf_wab.rb +1 -1
  98. data/test/sample/change.rb +0 -1
  99. data/test/sample/dir.rb +0 -1
  100. data/test/sample/doc.rb +0 -1
  101. data/test/sample/file.rb +0 -1
  102. data/test/sample/group.rb +0 -1
  103. data/test/sample/hasprops.rb +0 -1
  104. data/test/sample/layer.rb +0 -1
  105. data/test/sample/rect.rb +0 -1
  106. data/test/sample/shape.rb +0 -1
  107. data/test/sample/text.rb +0 -1
  108. data/test/sample.rb +2 -3
  109. data/test/sample_json.rb +0 -1
  110. data/test/test_compat.rb +11 -9
  111. data/test/test_custom.rb +5 -9
  112. data/test/test_debian.rb +1 -1
  113. data/test/test_fast.rb +10 -20
  114. data/test/test_file.rb +8 -8
  115. data/test/test_integer_range.rb +2 -2
  116. data/test/test_null.rb +5 -3
  117. data/test/test_object.rb +6 -5
  118. data/test/test_parser_saj.rb +23 -21
  119. data/test/test_parser_usual.rb +3 -3
  120. data/test/test_saj.rb +2 -0
  121. data/test/test_scp.rb +6 -6
  122. data/test/test_strict.rb +6 -4
  123. data/test/test_various.rb +21 -24
  124. data/test/test_wab.rb +6 -5
  125. data/test/test_writer.rb +1 -1
  126. metadata +20 -27
  127. data/test/activesupport4/decoding_test.rb +0 -108
  128. data/test/activesupport4/encoding_test.rb +0 -531
  129. data/test/activesupport4/test_helper.rb +0 -41
  130. data/test/activesupport5/abstract_unit.rb +0 -45
  131. data/test/activesupport5/decoding_test.rb +0 -133
  132. data/test/activesupport5/encoding_test.rb +0 -500
  133. data/test/activesupport5/encoding_test_cases.rb +0 -98
  134. data/test/activesupport5/test_helper.rb +0 -72
  135. data/test/activesupport5/time_zone_test_helpers.rb +0 -39
data/ext/oj/intern.c CHANGED
@@ -8,7 +8,9 @@
8
8
  #if HAVE_PTHREAD_MUTEX_INIT
9
9
  #include <pthread.h>
10
10
  #endif
11
+
11
12
  #include "cache.h"
13
+ #include "mem.h"
12
14
  #include "parse.h"
13
15
 
14
16
  // Only used for the class cache so 256 should be sufficient.
@@ -20,10 +22,10 @@
20
22
 
21
23
  typedef struct _keyVal {
22
24
  struct _keyVal *next;
23
- const char * key;
25
+ const char *key;
24
26
  size_t len;
25
27
  VALUE val;
26
- } * KeyVal;
28
+ } *KeyVal;
27
29
 
28
30
  typedef struct _hash {
29
31
  struct _keyVal slots[HASH_SLOT_CNT];
@@ -32,16 +34,16 @@ typedef struct _hash {
32
34
  #else
33
35
  VALUE mutex;
34
36
  #endif
35
- } * Hash;
37
+ } *Hash;
36
38
 
37
39
  struct _hash class_hash;
38
40
  struct _hash attr_hash;
39
41
 
40
- static VALUE str_cache_obj;
42
+ static VALUE str_cache_obj;
41
43
 
42
- static VALUE sym_cache_obj;
44
+ static VALUE sym_cache_obj;
43
45
 
44
- static VALUE attr_cache_obj;
46
+ static VALUE attr_cache_obj;
45
47
 
46
48
  static VALUE form_str(const char *str, size_t len) {
47
49
  return rb_str_freeze(rb_utf8_str_new(str, len));
@@ -55,30 +57,30 @@ static VALUE form_attr(const char *str, size_t len) {
55
57
  char buf[256];
56
58
 
57
59
  if (sizeof(buf) - 2 <= len) {
58
- char *b = ALLOC_N(char, len + 2);
60
+ char *b = OJ_R_ALLOC_N(char, len + 2);
59
61
  ID id;
60
62
 
61
63
  if ('~' == *str) {
62
- memcpy(b, str + 1, len - 1);
63
- b[len - 1] = '\0';
64
- len -= 2;
65
- } else {
66
- *b = '@';
67
- memcpy(b + 1, str, len);
68
- b[len + 1] = '\0';
69
- }
64
+ memcpy(b, str + 1, len - 1);
65
+ b[len - 1] = '\0';
66
+ len -= 2;
67
+ } else {
68
+ *b = '@';
69
+ memcpy(b + 1, str, len);
70
+ b[len + 1] = '\0';
71
+ }
70
72
  id = rb_intern3(buf, len + 1, oj_utf8_encoding);
71
- xfree(b);
73
+ OJ_R_FREE(b);
72
74
  return id;
73
75
  }
74
76
  if ('~' == *str) {
75
- memcpy(buf, str + 1, len - 1);
76
- buf[len - 1] = '\0';
77
- len -= 2;
77
+ memcpy(buf, str + 1, len - 1);
78
+ buf[len - 1] = '\0';
79
+ len -= 2;
78
80
  } else {
79
- *buf = '@';
80
- memcpy(buf + 1, str, len);
81
- buf[len + 1] = '\0';
81
+ *buf = '@';
82
+ memcpy(buf + 1, str, len);
83
+ buf[len + 1] = '\0';
82
84
  }
83
85
  return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
84
86
  }
@@ -87,19 +89,16 @@ void oj_hash_init(void) {
87
89
  VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
88
90
  rb_undef_alloc_func(cache_class);
89
91
 
90
- rb_gc_register_address(&cache_class);
91
- rb_undef_alloc_func(cache_class);
92
-
93
- struct _cache *str_cache = cache_create(0, form_str, true, true);
94
- str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
92
+ struct _cache *str_cache = cache_create(0, form_str, true, true);
93
+ str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
95
94
  rb_gc_register_address(&str_cache_obj);
96
95
 
97
- struct _cache *sym_cache = cache_create(0, form_sym, true, true);
98
- sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
96
+ struct _cache *sym_cache = cache_create(0, form_sym, true, true);
97
+ sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
99
98
  rb_gc_register_address(&sym_cache_obj);
100
99
 
101
100
  struct _cache *attr_cache = cache_create(0, form_attr, false, true);
102
- attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
101
+ attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
103
102
  rb_gc_register_address(&attr_cache_obj);
104
103
 
105
104
  memset(class_hash.slots, 0, sizeof(class_hash.slots));
@@ -125,12 +124,11 @@ oj_str_intern(const char *key, size_t len) {
125
124
 
126
125
  VALUE
127
126
  oj_sym_intern(const char *key, size_t len) {
128
- return cache_intern(DATA_PTR(sym_cache_obj), key, len);
127
+ return cache_intern(DATA_PTR(sym_cache_obj), key, len);
129
128
  }
130
129
 
131
- ID
132
- oj_attr_intern(const char *key, size_t len) {
133
- return cache_intern(DATA_PTR(attr_cache_obj), key, len);
130
+ ID oj_attr_intern(const char *key, size_t len) {
131
+ return cache_intern(DATA_PTR(attr_cache_obj), key, len);
134
132
  }
135
133
 
136
134
  static uint64_t hash_calc(const uint8_t *key, size_t len) {
@@ -184,10 +182,10 @@ static VALUE resolve_classname(VALUE mod, const char *classname, int auto_define
184
182
  static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
185
183
  char class_name[1024];
186
184
  VALUE clas;
187
- char * end = class_name + sizeof(class_name) - 1;
188
- char * s;
189
- const char *n = name;
190
- size_t nlen = len;
185
+ char *end = class_name + sizeof(class_name) - 1;
186
+ char *s;
187
+ const char *n = name;
188
+ size_t nlen = len;
191
189
 
192
190
  clas = rb_cObject;
193
191
  for (s = class_name; 0 < len; n++, len--) {
@@ -210,11 +208,11 @@ static VALUE resolve_classpath(ParseInfo pi, const char *name, size_t len, int a
210
208
  }
211
209
  *s = '\0';
212
210
  if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
213
- if (sizeof(class_name) <= nlen) {
214
- nlen = sizeof(class_name) - 1;
215
- }
216
- strncpy(class_name, name, nlen);
217
- class_name[nlen] = '\0';
211
+ if (sizeof(class_name) <= nlen) {
212
+ nlen = sizeof(class_name) - 1;
213
+ }
214
+ strncpy(class_name, name, nlen);
215
+ class_name[nlen] = '\0';
218
216
  oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class '%s' is not defined", class_name);
219
217
  if (Qnil != error_class) {
220
218
  pi->err_class = error_class;
@@ -246,7 +244,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
246
244
  }
247
245
  bucket = b;
248
246
  }
249
- b = ALLOC(struct _keyVal);
247
+ b = OJ_R_ALLOC(struct _keyVal);
250
248
  b->next = NULL;
251
249
  bucket->next = b;
252
250
  bucket = b;
@@ -267,7 +265,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
267
265
  }
268
266
  bucket = b;
269
267
  }
270
- b = ALLOC(struct _keyVal);
268
+ b = OJ_R_ALLOC(struct _keyVal);
271
269
  b->next = NULL;
272
270
  bucket->next = b;
273
271
  bucket = b;
@@ -281,7 +279,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
281
279
  }
282
280
 
283
281
  char *oj_strndup(const char *s, size_t len) {
284
- char *d = ALLOC_N(char, len + 1);
282
+ char *d = OJ_R_ALLOC_N(char, len + 1);
285
283
 
286
284
  memcpy(d, s, len);
287
285
  d[len] = '\0';
data/ext/oj/intern.h CHANGED
@@ -4,8 +4,8 @@
4
4
  #ifndef OJ_INTERN_H
5
5
  #define OJ_INTERN_H
6
6
 
7
- #include <stdbool.h>
8
7
  #include <ruby.h>
8
+ #include <stdbool.h>
9
9
 
10
10
  struct _parseInfo;
11
11
 
@@ -14,12 +14,8 @@ extern void oj_hash_init(void);
14
14
  extern VALUE oj_str_intern(const char *key, size_t len);
15
15
  extern VALUE oj_sym_intern(const char *key, size_t len);
16
16
  extern ID oj_attr_intern(const char *key, size_t len);
17
- extern VALUE oj_class_intern(const char * key,
18
- size_t len,
19
- bool safe,
20
- struct _parseInfo *pi,
21
- int auto_define,
22
- VALUE error_class);
17
+ extern VALUE
18
+ oj_class_intern(const char *key, size_t len, bool safe, struct _parseInfo *pi, int auto_define, VALUE error_class);
23
19
 
24
20
  extern char *oj_strndup(const char *s, size_t len);
25
21
 
data/ext/oj/mem.c ADDED
@@ -0,0 +1,318 @@
1
+ // Copyright (c) 2018, Peter Ohler, All rights reserved.
2
+
3
+ #include "mem.h"
4
+
5
+ #include <pthread.h>
6
+ #include <ruby.h>
7
+ #include <stdbool.h>
8
+ #include <stdint.h>
9
+ #include <stdio.h>
10
+ #include <stdlib.h>
11
+ #include <string.h>
12
+
13
+ typedef struct _rec {
14
+ struct _rec *next;
15
+ const void *ptr;
16
+ size_t size;
17
+ const char *file;
18
+ int line;
19
+ bool ruby;
20
+ } *Rec;
21
+
22
+ typedef struct _rep {
23
+ struct _rep *next;
24
+ size_t size;
25
+ const char *file;
26
+ int line;
27
+ int cnt;
28
+ } *Rep;
29
+
30
+ #ifdef MEM_DEBUG
31
+
32
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
33
+ static Rec recs = NULL;
34
+ static const char mem_pad[] = "--- This is a memory pad and should not change until being freed. ---";
35
+
36
+ void *oj_malloc(size_t size, const char *file, int line) {
37
+ void *ptr = malloc(size + sizeof(mem_pad));
38
+
39
+ if (NULL != ptr) {
40
+ Rec r = (Rec)malloc(sizeof(struct _rec));
41
+
42
+ if (NULL != r) {
43
+ strcpy(((char *)ptr) + size, mem_pad);
44
+ r->ptr = ptr;
45
+ r->size = size;
46
+ r->file = file;
47
+ r->line = line;
48
+ r->ruby = false;
49
+ pthread_mutex_lock(&lock);
50
+ r->next = recs;
51
+ recs = r;
52
+ pthread_mutex_unlock(&lock);
53
+ } else {
54
+ free(ptr);
55
+ ptr = NULL;
56
+ }
57
+ }
58
+ return ptr;
59
+ }
60
+
61
+ void *oj_realloc(void *orig, size_t size, const char *file, int line) {
62
+ void *ptr = realloc(orig, size + sizeof(mem_pad));
63
+ Rec r;
64
+
65
+ if (NULL != ptr) {
66
+ strcpy(((char *)ptr) + size, mem_pad);
67
+ pthread_mutex_lock(&lock);
68
+ for (r = recs; NULL != r; r = r->next) {
69
+ if (orig == r->ptr) {
70
+ r->ptr = ptr;
71
+ r->size = size;
72
+ r->file = file;
73
+ r->line = line;
74
+ r->ruby = false;
75
+ break;
76
+ }
77
+ }
78
+ pthread_mutex_unlock(&lock);
79
+ if (NULL == r) {
80
+ printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
81
+ }
82
+ }
83
+ return ptr;
84
+ }
85
+
86
+ void *oj_calloc(size_t count, size_t size, const char *file, int line) {
87
+ void *ptr;
88
+
89
+ size *= count;
90
+ if (NULL != (ptr = malloc(size + sizeof(mem_pad)))) {
91
+ Rec r = (Rec)malloc(sizeof(struct _rec));
92
+
93
+ if (NULL != r) {
94
+ memset(ptr, 0, size);
95
+ strcpy(((char *)ptr) + size, mem_pad);
96
+ r->ptr = ptr;
97
+ r->size = size;
98
+ r->file = file;
99
+ r->line = line;
100
+ r->ruby = false;
101
+ pthread_mutex_lock(&lock);
102
+ r->next = recs;
103
+ recs = r;
104
+ pthread_mutex_unlock(&lock);
105
+ } else {
106
+ free(ptr);
107
+ ptr = NULL;
108
+ }
109
+ }
110
+ return ptr;
111
+ }
112
+
113
+ void *oj_r_alloc(size_t size, const char *file, int line) {
114
+ void *ptr = ruby_xmalloc(size + sizeof(mem_pad));
115
+
116
+ if (NULL != ptr) {
117
+ Rec r = (Rec)malloc(sizeof(struct _rec));
118
+
119
+ if (NULL != r) {
120
+ strcpy(((char *)ptr) + size, mem_pad);
121
+ r->ptr = ptr;
122
+ r->size = size;
123
+ r->file = file;
124
+ r->line = line;
125
+ r->ruby = true;
126
+ pthread_mutex_lock(&lock);
127
+ r->next = recs;
128
+ recs = r;
129
+ pthread_mutex_unlock(&lock);
130
+ } else {
131
+ free(ptr);
132
+ ptr = NULL;
133
+ }
134
+ }
135
+ return ptr;
136
+ }
137
+
138
+ void *oj_r_realloc(void *orig, size_t size, const char *file, int line) {
139
+ void *ptr = ruby_xrealloc2(orig, 1, size + sizeof(mem_pad));
140
+ Rec r;
141
+
142
+ if (NULL != ptr) {
143
+ strcpy(((char *)ptr) + size, mem_pad);
144
+ pthread_mutex_lock(&lock);
145
+ for (r = recs; NULL != r; r = r->next) {
146
+ if (orig == r->ptr) {
147
+ r->ptr = ptr;
148
+ r->size = size;
149
+ r->file = file;
150
+ r->line = line;
151
+ r->ruby = true;
152
+ break;
153
+ }
154
+ }
155
+ pthread_mutex_unlock(&lock);
156
+ if (NULL == r) {
157
+ printf("Realloc at %s:%d (%p) not allocated.\n", file, line, orig);
158
+ }
159
+ }
160
+ return ptr;
161
+ }
162
+
163
+ void oj_freed(void *ptr, const char *file, int line, bool ruby) {
164
+ if (NULL != ptr) {
165
+ Rec r = NULL;
166
+ Rec prev = NULL;
167
+
168
+ pthread_mutex_lock(&lock);
169
+ for (r = recs; NULL != r; r = r->next) {
170
+ if (ptr == r->ptr) {
171
+ if (NULL == prev) {
172
+ recs = r->next;
173
+ } else {
174
+ prev->next = r->next;
175
+ }
176
+ break;
177
+ }
178
+ prev = r;
179
+ }
180
+ pthread_mutex_unlock(&lock);
181
+ if (NULL == r) {
182
+ printf("Free at %s:%d (%p) not allocated or already freed.\n", file, line, ptr);
183
+ } else {
184
+ char *pad = (char *)r->ptr + r->size;
185
+
186
+ if (r->ruby != ruby) {
187
+ if (r->ruby) {
188
+ printf("Memory at %s:%d (%p) allocated with Ruby allocator and freed with stdlib free.\n",
189
+ file,
190
+ line,
191
+ ptr);
192
+ } else {
193
+ printf("Memory at %s:%d (%p) allocated with stdlib allocator and freed with Ruby free.\n",
194
+ file,
195
+ line,
196
+ ptr);
197
+ }
198
+ }
199
+ if (0 != strcmp(mem_pad, pad)) {
200
+ uint8_t *p;
201
+ uint8_t *end = (uint8_t *)pad + sizeof(mem_pad);
202
+
203
+ printf("Memory at %s:%d (%p) write outside allocated.\n", file, line, ptr);
204
+ for (p = (uint8_t *)pad; p < end; p++) {
205
+ if (0x20 < *p && *p < 0x7f) {
206
+ printf("%c ", *p);
207
+ } else {
208
+ printf("%02x ", *(uint8_t *)p);
209
+ }
210
+ }
211
+ printf("\n");
212
+ }
213
+ free(r);
214
+ }
215
+ }
216
+ }
217
+
218
+ void oj_r_free(void *ptr, const char *file, int line) {
219
+ oj_freed(ptr, file, line, true);
220
+ xfree(ptr);
221
+ }
222
+
223
+ void oj_free(void *ptr, const char *file, int line) {
224
+ oj_freed(ptr, file, line, false);
225
+ free(ptr);
226
+ }
227
+
228
+ char *oj_mem_strdup(const char *str, const char *file, int line) {
229
+ size_t size = strlen(str) + 1;
230
+ char *ptr = (char *)malloc(size + sizeof(mem_pad));
231
+
232
+ if (NULL != ptr) {
233
+ Rec r = (Rec)malloc(sizeof(struct _rec));
234
+
235
+ if (NULL != r) {
236
+ strcpy(ptr, str);
237
+ strcpy(((char *)ptr) + size, mem_pad);
238
+ r->ptr = (void *)ptr;
239
+ r->size = size;
240
+ r->file = file;
241
+ r->line = line;
242
+ r->ruby = false;
243
+ pthread_mutex_lock(&lock);
244
+ r->next = recs;
245
+ recs = r;
246
+ pthread_mutex_unlock(&lock);
247
+ } else {
248
+ free(ptr);
249
+ ptr = NULL;
250
+ }
251
+ }
252
+ return ptr;
253
+ }
254
+
255
+ #endif
256
+
257
+ #ifdef MEM_DEBUG
258
+
259
+ static Rep update_reps(Rep reps, Rec r) {
260
+ Rep rp = reps;
261
+
262
+ for (; NULL != rp; rp = rp->next) {
263
+ if (rp->line == r->line && (rp->file == r->file || 0 == strcmp(rp->file, r->file))) {
264
+ rp->size += r->size;
265
+ rp->cnt++;
266
+ break;
267
+ }
268
+ }
269
+ if (NULL == rp && NULL != (rp = (Rep)malloc(sizeof(struct _rep)))) {
270
+ rp->size = r->size;
271
+ rp->file = r->file;
272
+ rp->line = r->line;
273
+ rp->cnt = 1;
274
+ rp->next = reps;
275
+ reps = rp;
276
+ }
277
+ return reps;
278
+ }
279
+
280
+ static void print_stats() {
281
+ printf("\n--- Memory Usage Report --------------------------------------------------------\n");
282
+ pthread_mutex_lock(&lock);
283
+
284
+ if (NULL == recs) {
285
+ printf("No memory leaks\n");
286
+ } else {
287
+ Rep reps = NULL;
288
+ Rep rp;
289
+ Rec r;
290
+ size_t leaked = 0;
291
+
292
+ for (r = recs; NULL != r; r = r->next) {
293
+ reps = update_reps(reps, r);
294
+ }
295
+ while (NULL != (rp = reps)) {
296
+ reps = rp->next;
297
+ printf("%16s:%3d %8lu bytes over %d occurances allocated and not freed.\n",
298
+ rp->file,
299
+ rp->line,
300
+ rp->size,
301
+ rp->cnt);
302
+ leaked += rp->size;
303
+ free(rp);
304
+ }
305
+ printf("%lu bytes leaked\n", leaked);
306
+ }
307
+ pthread_mutex_unlock(&lock);
308
+ printf("--------------------------------------------------------------------------------\n");
309
+ }
310
+
311
+ #endif
312
+
313
+ void oj_mem_report(void) {
314
+ #ifdef MEM_DEBUG
315
+ rb_gc();
316
+ print_stats();
317
+ #endif
318
+ }
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
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "dump.h"
5
5
  #include "encode.h"
6
+ #include "mem.h"
6
7
  #include "oj.h"
7
8
  #include "parse.h"
8
9
 
@@ -348,12 +349,11 @@ static VALUE mimic_load(int argc, VALUE *argv, VALUE self) {
348
349
  static VALUE mimic_dump_load(int argc, VALUE *argv, VALUE self) {
349
350
  if (1 > argc) {
350
351
  rb_raise(rb_eArgError, "wrong number of arguments (0 for 1)");
351
- } else if (T_STRING == rb_type(*argv)) {
352
+ }
353
+ if (T_STRING == rb_type(*argv)) {
352
354
  return mimic_load(argc, argv, self);
353
- } else {
354
- return mimic_dump(argc, argv, self);
355
355
  }
356
- return Qnil;
356
+ return mimic_dump(argc, argv, self);
357
357
  }
358
358
 
359
359
  static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
@@ -367,8 +367,8 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
367
367
 
368
368
  oj_out_init(&out);
369
369
 
370
- out.omit_nil = copts->dump_opts.omit_nil;
371
- out.caller = CALLER_GENERATE;
370
+ out.omit_nil = copts->dump_opts.omit_nil;
371
+ out.caller = CALLER_GENERATE;
372
372
  // For obj.to_json or generate nan is not allowed but if called from dump
373
373
  // it is.
374
374
  copts->dump_opts.nan_dump = RaiseNan;
@@ -388,10 +388,8 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
388
388
  VALUE active_hack[1];
389
389
 
390
390
  if (Qundef == state_class) {
391
- rb_warn(
392
- "Oj::Rails.mimic_JSON was called implicitly. "
393
- "Call it explicitly beforehand if you want to remove this warning."
394
- );
391
+ rb_warn("Oj::Rails.mimic_JSON was called implicitly. "
392
+ "Call it explicitly beforehand if you want to remove this warning.");
395
393
  oj_define_mimic_json(0, NULL, Qnil);
396
394
  }
397
395
  active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
@@ -466,7 +464,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
466
464
  }
467
465
  if (1 == argc || Qnil == argv[1]) {
468
466
  h = rb_hash_new();
469
- } else {
467
+ } else {
470
468
  h = argv[1];
471
469
  }
472
470
  if (!oj_hash_has_key(h, oj_indent_sym)) {
@@ -485,10 +483,8 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
485
483
  rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
486
484
  }
487
485
  if (Qundef == state_class) {
488
- rb_warn(
489
- "Oj::Rails.mimic_JSON was called implicitly. "
490
- "Call it explicitly beforehand if you want to remove this warning."
491
- );
486
+ rb_warn("Oj::Rails.mimic_JSON was called implicitly. "
487
+ "Call it explicitly beforehand if you want to remove this warning.");
492
488
  oj_define_mimic_json(0, NULL, Qnil);
493
489
  }
494
490
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
@@ -657,23 +653,22 @@ static VALUE mimic_recurse_proc(VALUE self, VALUE obj) {
657
653
  *
658
654
  * - *id* [_nil_|String] new create_id
659
655
  *
660
- * Returns [_String_] the id.
656
+ * Returns [_nil_|_String_] the id.
661
657
  */
662
658
  static VALUE mimic_set_create_id(VALUE self, VALUE id) {
663
- Check_Type(id, T_STRING);
664
-
665
659
  if (NULL != oj_default_options.create_id) {
666
660
  if (oj_json_class != oj_default_options.create_id) {
667
- xfree((char *)oj_default_options.create_id);
661
+ OJ_R_FREE((char *)oj_default_options.create_id);
668
662
  }
669
663
  oj_default_options.create_id = NULL;
670
664
  oj_default_options.create_id_len = 0;
671
665
  }
672
666
  if (Qnil != id) {
673
- size_t len = RSTRING_LEN(id) + 1;
667
+ const char *ptr = StringValueCStr(id);
668
+ size_t len = RSTRING_LEN(id) + 1;
674
669
 
675
- oj_default_options.create_id = ALLOC_N(char, len);
676
- strcpy((char *)oj_default_options.create_id, StringValuePtr(id));
670
+ oj_default_options.create_id = OJ_R_ALLOC_N(char, len);
671
+ strcpy((char *)oj_default_options.create_id, ptr);
677
672
  oj_default_options.create_id_len = len - 1;
678
673
  }
679
674
  return id;
@@ -762,9 +757,9 @@ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
762
757
 
763
758
  oj_out_init(&out);
764
759
 
765
- out.omit_nil = copts.dump_opts.omit_nil;
766
- copts.mode = CompatMode;
767
- copts.to_json = No;
760
+ out.omit_nil = copts.dump_opts.omit_nil;
761
+ copts.mode = CompatMode;
762
+ copts.to_json = No;
768
763
  if (1 <= argc && Qnil != argv[0]) {
769
764
  oj_parse_mimic_dump_options(argv[0], &copts);
770
765
  }