yajl-ruby 1.4.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of yajl-ruby might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: c99601133192fb2ea1f0586ac1b4a83dc465d9a8
4
- data.tar.gz: cbfce4619e6c2ccd5b761bf8d6005dbee6ce043e
2
+ SHA256:
3
+ metadata.gz: dcd3ae6509fd5f45b1527644b221e2ec44e4f697ef0ef5d92399aee3567ad7a6
4
+ data.tar.gz: 0045452d11da4b6b6fbcdf965fd94d0d43655245cb68fca518bfddc38513ad6c
5
5
  SHA512:
6
- metadata.gz: 78c816a3a6368d3b0520d27b5987da10a40478357424e305aa121a6359141ef51c8ee9a3caa4bc3dde159156d5cb6f9af6d5cfd3c576c543b5fd9178ad2993e6
7
- data.tar.gz: fc968516c955984c03c184d11a349c82c109adcce8c590a7537bd291a315bb2a8ac0be92ae927b9458e10dee07b564ebf15806bc591b89b0d09df89b5d6ce173
6
+ metadata.gz: 4cf495e84d645c644aa62233af8e0498da2b22fdf46f7071694df93af61d7b30785f2d0c1f73932979f92c5f94530427b018fb0bceb94ed5121de0c0fe792b15
7
+ data.tar.gz: bbe72bfd0fd3d0c544557a0bbe7580b5ef33b893ce7df0ef01d40b653d0defdbce963091b9f21fe897082778a3587d9962c4fc10e41bb270c8d32706ef7478b1
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ strategy:
8
+ matrix:
9
+ ruby_version: [2.6.x, 2.7.x, 3.0.x]
10
+ fail-fast: false
11
+ runs-on: ubuntu-latest
12
+ name: Test on Ruby ${{ matrix.ruby_version }}
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Setup Ruby ${{ matrix.ruby_version }}
16
+ uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby_version }}
19
+ - name: Install dependencies
20
+ run: bundle install
21
+ - name: Build gem
22
+ run: gem build yajl-ruby.gemspec
23
+ - name: Install gem
24
+ run: gem install yajl-ruby
25
+ - name: Run tests
26
+ run: bundle exec rake spec
data/README.md CHANGED
@@ -126,7 +126,7 @@ url = URI.parse("http://search.twitter.com/search.json?q=engineyard")
126
126
  results = Yajl::HttpStream.get(url)
127
127
  ```
128
128
 
129
- Since yajl-ruby parses JSON as a stream, supporting API's like Twitter's Streaming API are a piece-of-cake.
129
+ Since yajl-ruby parses JSON as a stream, supporting APIs like Twitter's Streaming API are a piece-of-cake.
130
130
  You can simply supply a block to `Yajl::HttpStream.get`, which is used as the callback for when a JSON object has been
131
131
  unserialized off the stream. For the case of this Twitter Streaming API call, the callback gets fired a few times a second (depending on your connection speed).
132
132
  The code below is all that's needed to make the request and stream unserialized Ruby hashes off the response, continuously.
@@ -56,6 +56,12 @@ extern "C" {
56
56
  # endif
57
57
  #endif
58
58
 
59
+ #if defined(__GNUC__)
60
+ #define YAJL_WARN_UNUSED __attribute__ ((warn_unused_result))
61
+ #else
62
+ #define YAJL_WARN_UNUSED
63
+ #endif
64
+
59
65
  /** pointer to a malloc function, supporting client overriding memory
60
66
  * allocation routines */
61
67
  typedef void * (*yajl_malloc_func)(void *ctx, unsigned int sz);
@@ -63,7 +63,11 @@ extern "C" {
63
63
  yajl_gen_invalid_number,
64
64
  /** A print callback was passed in, so there is no internal
65
65
  * buffer to get from */
66
- yajl_gen_no_buf
66
+ yajl_gen_no_buf,
67
+ /** Tried to decrement at depth 0 */
68
+ yajl_depth_underflow,
69
+ /** Allocation error */
70
+ yajl_gen_alloc_error
67
71
  } yajl_gen_status;
68
72
 
69
73
  /** an opaque handle to a generator */
@@ -129,6 +133,7 @@ extern "C" {
129
133
  * NaN, as these have no representation in JSON. In these cases the
130
134
  * generator will return 'yajl_gen_invalid_number' */
131
135
  YAJL_API yajl_gen_status yajl_gen_double(yajl_gen hand, double number);
136
+ YAJL_API yajl_gen_status yajl_gen_long(yajl_gen hand, long value);
132
137
  YAJL_API yajl_gen_status yajl_gen_number(yajl_gen hand,
133
138
  const char * num,
134
139
  unsigned int len);
@@ -145,7 +150,7 @@ extern "C" {
145
150
  /** access the null terminated generator buffer. If incrementally
146
151
  * outputing JSON, one should call yajl_gen_clear to clear the
147
152
  * buffer. This allows stream generation. */
148
- YAJL_API yajl_gen_status yajl_gen_get_buf(yajl_gen hand,
153
+ YAJL_API YAJL_WARN_UNUSED yajl_gen_status yajl_gen_get_buf(yajl_gen hand,
149
154
  const unsigned char ** buf,
150
155
  unsigned int * len);
151
156
 
@@ -55,7 +55,9 @@ extern "C" {
55
55
  yajl_status_insufficient_data,
56
56
  /** An error occured during the parse. Call yajl_get_error for
57
57
  * more information about the encountered error */
58
- yajl_status_error
58
+ yajl_status_error,
59
+ /** an allocation failed */
60
+ yajl_status_alloc_failed,
59
61
  } yajl_status;
60
62
 
61
63
  /** attain a human readable, english, string for an error */
data/ext/yajl/extconf.rb CHANGED
@@ -4,4 +4,9 @@ require 'rbconfig'
4
4
  $CFLAGS << ' -Wall -funroll-loops -Wno-declaration-after-statement'
5
5
  $CFLAGS << ' -Werror-implicit-function-declaration -Wextra -O0 -ggdb3' if ENV['DEBUG']
6
6
 
7
+ if ENV['SANITIZE']
8
+ $CFLAGS << ' -fsanitize=address'
9
+ $LDFLAGS << ' -fsanitize=address'
10
+ end
11
+
7
12
  create_makefile('yajl/yajl')
data/ext/yajl/yajl.c CHANGED
@@ -56,6 +56,9 @@ yajl_status_to_string(yajl_status stat)
56
56
  case yajl_status_error:
57
57
  statStr = "parse error";
58
58
  break;
59
+ case yajl_status_alloc_failed:
60
+ statStr = "allocation failed";
61
+ break;
59
62
  }
60
63
  return statStr;
61
64
  }
@@ -83,6 +86,8 @@ yajl_alloc(const yajl_callbacks * callbacks,
83
86
  }
84
87
 
85
88
  hand = (yajl_handle) YA_MALLOC(afs, sizeof(struct yajl_handle_t));
89
+ if (hand == NULL)
90
+ return NULL;
86
91
 
87
92
  /* copy in pointers to allocation routines */
88
93
  memcpy((void *) &(hand->alloc), (void *) afs, sizeof(yajl_alloc_funcs));
@@ -95,23 +100,31 @@ yajl_alloc(const yajl_callbacks * callbacks,
95
100
  hand->callbacks = callbacks;
96
101
  hand->ctx = ctx;
97
102
  hand->lexer = yajl_lex_alloc(&(hand->alloc), allowComments, validateUTF8);
103
+ if (!hand->lexer) {
104
+ YA_FREE(afs, hand);
105
+ return NULL;
106
+ }
98
107
  hand->bytesConsumed = 0;
99
108
  hand->decodeBuf = yajl_buf_alloc(&(hand->alloc));
100
109
  yajl_bs_init(hand->stateStack, &(hand->alloc));
101
110
 
102
- yajl_bs_push(hand->stateStack, yajl_state_start);
111
+ if (yajl_bs_push(hand->stateStack, yajl_state_start)) {
112
+ return NULL;
113
+ }
103
114
 
104
115
  return hand;
105
116
  }
106
117
 
107
118
  void
108
119
  yajl_reset_parser(yajl_handle hand) {
120
+ assert(hand);
109
121
  hand->lexer = yajl_lex_realloc(hand->lexer);
110
122
  }
111
123
 
112
124
  void
113
125
  yajl_free(yajl_handle handle)
114
126
  {
127
+ assert(handle);
115
128
  yajl_bs_free(handle->stateStack);
116
129
  yajl_buf_free(handle->decodeBuf);
117
130
  yajl_lex_free(handle->lexer);
@@ -122,6 +135,7 @@ yajl_status
122
135
  yajl_parse(yajl_handle hand, const unsigned char * jsonText,
123
136
  unsigned int jsonTextLen)
124
137
  {
138
+ assert(hand);
125
139
  yajl_status status;
126
140
  status = yajl_do_parse(hand, jsonText, jsonTextLen);
127
141
  return status;
@@ -130,6 +144,7 @@ yajl_parse(yajl_handle hand, const unsigned char * jsonText,
130
144
  yajl_status
131
145
  yajl_parse_complete(yajl_handle hand)
132
146
  {
147
+ assert(hand);
133
148
  /* The particular case we want to handle is a trailing number.
134
149
  * Further input consisting of digits could cause our interpretation
135
150
  * of the number to change (buffered "1" but "2" comes in).
@@ -143,6 +158,7 @@ unsigned char *
143
158
  yajl_get_error(yajl_handle hand, int verbose,
144
159
  const unsigned char * jsonText, unsigned int jsonTextLen)
145
160
  {
161
+ assert(hand);
146
162
  return yajl_render_error_string(hand, jsonText, jsonTextLen, verbose);
147
163
  }
148
164
 
data/ext/yajl/yajl_buf.c CHANGED
@@ -35,43 +35,114 @@
35
35
  #include <assert.h>
36
36
  #include <stdlib.h>
37
37
  #include <string.h>
38
+ #include <stdio.h>
38
39
 
39
40
  #define YAJL_BUF_INIT_SIZE 2048
40
41
 
41
42
  struct yajl_buf_t {
43
+ yajl_buf_state state;
42
44
  unsigned int len;
43
45
  unsigned int used;
44
46
  unsigned char * data;
45
47
  yajl_alloc_funcs * alloc;
46
48
  };
47
49
 
50
+ static void *noop_realloc(void *ctx, void *ptr, unsigned int sz) {
51
+ fprintf(stderr, "Attempt to allocate on invalid yajl_buf_t\n");
52
+ abort();
53
+ }
54
+ static void *noop_malloc(void *ctx, unsigned int sz) { return noop_realloc(ctx, NULL, sz); }
55
+ static void noop_free(void *ctx, void *ptr) { }
56
+
57
+ static yajl_alloc_funcs noop_allocs = {
58
+ .malloc = &noop_malloc,
59
+ .realloc = &noop_realloc,
60
+ .free = &noop_free,
61
+ };
62
+
63
+ // A buffer to be returned if the initial allocation fails
64
+ static struct yajl_buf_t buf_alloc_error = {
65
+ .state = yajl_buf_alloc_failed,
66
+ .alloc = &noop_allocs
67
+ };
68
+
69
+ #include <stdio.h>
70
+
71
+ yajl_buf_state yajl_buf_err(yajl_buf buf)
72
+ {
73
+ assert(buf);
74
+ return buf->state;
75
+ }
76
+
77
+ static
78
+ yajl_buf_state yajl_buf_set_error(yajl_buf buf, yajl_buf_state err)
79
+ {
80
+ buf->state = err;
81
+
82
+ // free and clear all data from the buffer
83
+ YA_FREE(buf->alloc, buf->data);
84
+ buf->len = 0;
85
+ buf->data = 0;
86
+ buf->used = 0;
87
+
88
+ return err;
89
+ }
90
+
48
91
  static
49
- void yajl_buf_ensure_available(yajl_buf buf, unsigned int want)
92
+ yajl_buf_state yajl_buf_ensure_available(yajl_buf buf, unsigned int want)
50
93
  {
51
94
  unsigned int need;
52
95
 
53
96
  assert(buf != NULL);
54
97
 
98
+ if (buf->state != yajl_buf_ok) {
99
+ return buf->state;
100
+ }
101
+
55
102
  /* first call */
56
103
  if (buf->data == NULL) {
57
104
  buf->len = YAJL_BUF_INIT_SIZE;
58
105
  buf->data = (unsigned char *) YA_MALLOC(buf->alloc, buf->len);
106
+ if (buf->data == NULL) {
107
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
108
+ }
109
+
59
110
  buf->data[0] = 0;
60
111
  }
61
112
 
113
+ if (want == 0) {
114
+ return yajl_buf_ok;
115
+ }
116
+
62
117
  need = buf->len;
63
118
 
64
119
  while (want >= (need - buf->used)) need <<= 1;
65
120
 
121
+ // Check for overflow
122
+ if (need < buf->used) {
123
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
124
+ }
125
+
66
126
  if (need != buf->len) {
67
127
  buf->data = (unsigned char *) YA_REALLOC(buf->alloc, buf->data, need);
128
+
129
+ if (buf->data == NULL) {
130
+ return yajl_buf_set_error(buf, yajl_buf_overflow);
131
+ }
132
+
68
133
  buf->len = need;
69
134
  }
135
+
136
+ return yajl_buf_ok;
70
137
  }
71
138
 
72
139
  yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc)
73
140
  {
74
141
  yajl_buf b = YA_MALLOC(alloc, sizeof(struct yajl_buf_t));
142
+ if (b == NULL) {
143
+ return &buf_alloc_error;
144
+ }
145
+
75
146
  memset((void *) b, 0, sizeof(struct yajl_buf_t));
76
147
  b->alloc = alloc;
77
148
  return b;
@@ -86,7 +157,9 @@ void yajl_buf_free(yajl_buf buf)
86
157
 
87
158
  void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len)
88
159
  {
89
- yajl_buf_ensure_available(buf, len);
160
+ if (yajl_buf_ensure_available(buf, len)) {
161
+ return;
162
+ }
90
163
  if (len > 0) {
91
164
  assert(data != NULL);
92
165
  memcpy(buf->data + buf->used, data, len);
@@ -97,23 +170,31 @@ void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len)
97
170
 
98
171
  void yajl_buf_clear(yajl_buf buf)
99
172
  {
173
+ assert(buf);
174
+ assert(!yajl_buf_err(buf));
100
175
  buf->used = 0;
101
176
  if (buf->data) buf->data[buf->used] = 0;
102
177
  }
103
178
 
104
179
  const unsigned char * yajl_buf_data(yajl_buf buf)
105
180
  {
181
+ assert(buf);
182
+ assert(!yajl_buf_err(buf));
106
183
  return buf->data;
107
184
  }
108
185
 
109
186
  unsigned int yajl_buf_len(yajl_buf buf)
110
187
  {
188
+ assert(buf);
189
+ assert(!yajl_buf_err(buf));
111
190
  return buf->used;
112
191
  }
113
192
 
114
193
  void
115
194
  yajl_buf_truncate(yajl_buf buf, unsigned int len)
116
195
  {
196
+ assert(buf);
197
+ assert(!yajl_buf_err(buf));
117
198
  assert(len <= buf->used);
118
199
  buf->used = len;
119
200
  }
data/ext/yajl/yajl_buf.h CHANGED
@@ -43,6 +43,12 @@
43
43
  * call overhead. YMMV.
44
44
  */
45
45
 
46
+ typedef enum {
47
+ yajl_buf_ok = 0,
48
+ yajl_buf_alloc_failed,
49
+ yajl_buf_overflow
50
+ } yajl_buf_state;
51
+
46
52
  /**
47
53
  * yajl_buf is a buffer with exponential growth. the buffer ensures that
48
54
  * you are always null padded.
@@ -77,4 +83,7 @@ unsigned int yajl_buf_len(yajl_buf buf);
77
83
  YAJL_API
78
84
  void yajl_buf_truncate(yajl_buf buf, unsigned int len);
79
85
 
86
+ /* get the state of buffer */
87
+ yajl_buf_state yajl_buf_err(yajl_buf buf);
88
+
80
89
  #endif
@@ -38,9 +38,12 @@
38
38
  #ifndef __YAJL_BYTESTACK_H__
39
39
  #define __YAJL_BYTESTACK_H__
40
40
 
41
+ #include <limits.h>
42
+ #include <assert.h>
41
43
  #include "api/yajl_common.h"
42
44
 
43
45
  #define YAJL_BS_INC 128
46
+ #define YAJL_BS_MAX_SIZE UINT_MAX
44
47
 
45
48
  typedef struct yajl_bytestack_t
46
49
  {
@@ -66,20 +69,34 @@ typedef struct yajl_bytestack_t
66
69
  #define yajl_bs_current(obs) \
67
70
  (assert((obs).used > 0), (obs).stack[(obs).used - 1])
68
71
 
69
- #define yajl_bs_push(obs, byte) { \
70
- if (((obs).size - (obs).used) == 0) { \
71
- (obs).size += YAJL_BS_INC; \
72
- (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\
73
- (void *) (obs).stack, (obs).size);\
74
- } \
75
- (obs).stack[((obs).used)++] = (byte); \
72
+ /* 0: success, 1: error */
73
+ static inline YAJL_WARN_UNUSED
74
+ int yajl_bs_push_inline(yajl_bytestack *obs, unsigned char byte) {
75
+ if ((obs->size - obs->used) == 0) {
76
+ if (obs->size > YAJL_BS_MAX_SIZE - YAJL_BS_INC)
77
+ return 1;
78
+ obs->size += YAJL_BS_INC;
79
+ obs->stack = obs->yaf->realloc(obs->yaf->ctx, (void *)obs->stack, obs->size);
80
+ if (!obs->stack)
81
+ return 1;
82
+ }
83
+ obs->stack[obs->used++] = byte;
84
+ return 0;
76
85
  }
77
-
86
+
87
+ #define yajl_bs_push(obs, byte) yajl_bs_push_inline(&(obs), (byte))
88
+
78
89
  /* removes the top item of the stack, returns nothing */
79
90
  #define yajl_bs_pop(obs) { ((obs).used)--; }
80
91
 
81
- #define yajl_bs_set(obs, byte) \
82
- (obs).stack[((obs).used) - 1] = (byte);
83
-
92
+ static inline
93
+ void
94
+ yajl_bs_set_inline(yajl_bytestack *obs, unsigned char byte) {
95
+ assert(obs->used > 0);
96
+ assert(obs->size >= obs->used);
97
+ obs->stack[obs->used - 1] = byte;
98
+ }
99
+
100
+ #define yajl_bs_set(obs, byte) yajl_bs_set_inline(&obs, byte)
84
101
 
85
102
  #endif
data/ext/yajl/yajl_ext.c CHANGED
@@ -93,7 +93,11 @@ static char *yajl_raise_encode_error_for_status(yajl_gen_status status, VALUE ob
93
93
  rb_raise(cEncodeError, "Invalid number: cannot encode Infinity, -Infinity, or NaN");
94
94
  case yajl_gen_no_buf:
95
95
  rb_raise(cEncodeError, "YAJL internal error: yajl_gen_get_buf was called, but a print callback was specified, so no internal buffer is available");
96
+ case yajl_gen_alloc_error:
97
+ rb_raise(cEncodeError, "YAJL internal error: failed to allocate memory");
96
98
  default:
99
+ // fixme: why wasn't this already here??
100
+ rb_raise(cEncodeError, "Encountered unknown YAJL status %d during JSON generation", status);
97
101
  return NULL;
98
102
  }
99
103
  }
@@ -155,18 +159,47 @@ static void yajl_encoder_wrapper_mark(void * wrapper) {
155
159
  }
156
160
  }
157
161
 
162
+ static VALUE yajl_key_to_string(VALUE obj) {
163
+ switch (TYPE(obj)) {
164
+ case T_STRING:
165
+ return obj;
166
+ case T_SYMBOL:
167
+ return rb_sym2str(obj);
168
+ default:
169
+ return rb_funcall(obj, intern_to_s, 0);
170
+ }
171
+ }
172
+
173
+ void yajl_encode_part(void * wrapper, VALUE obj, VALUE io);
174
+ struct yajl_encode_hash_iter {
175
+ void *w;
176
+ VALUE io;
177
+ };
178
+
179
+ static int yajl_encode_part_hash_i(VALUE key, VALUE val, VALUE iter_v) {
180
+ struct yajl_encode_hash_iter *iter = (struct yajl_encode_hash_iter *)iter_v;
181
+ /* key must be a string */
182
+ VALUE keyStr = yajl_key_to_string(key);
183
+
184
+ /* the key */
185
+ yajl_encode_part(iter->w, keyStr, iter->io);
186
+ /* the value */
187
+ yajl_encode_part(iter->w, val, iter->io);
188
+
189
+ return ST_CONTINUE;
190
+ }
191
+
158
192
  #define CHECK_STATUS(call) \
159
193
  if ((status = (call)) != yajl_gen_status_ok) { break; }
160
194
 
161
195
  void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) {
162
- VALUE str, outBuff, otherObj;
196
+ VALUE str, outBuff;
163
197
  yajl_encoder_wrapper * w = wrapper;
164
198
  yajl_gen_status status;
165
199
  int idx = 0;
166
200
  const unsigned char * buffer;
167
201
  const char * cptr;
168
202
  unsigned int len;
169
- VALUE keys, entry, keyStr;
170
203
 
171
204
  if (io != Qnil || w->on_progress_callback != Qnil) {
172
205
  status = yajl_gen_get_buf(w->encoder, &buffer, &len);
@@ -188,24 +221,19 @@ void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) {
188
221
  case T_HASH:
189
222
  CHECK_STATUS(yajl_gen_map_open(w->encoder));
190
223
 
191
- /* TODO: itterate through keys in the hash */
192
- keys = rb_funcall(obj, intern_keys, 0);
193
- for(idx=0; idx<RARRAY_LEN(keys); idx++) {
194
- entry = rb_ary_entry(keys, idx);
195
- keyStr = rb_funcall(entry, intern_to_s, 0); /* key must be a string */
196
- /* the key */
197
- yajl_encode_part(w, keyStr, io);
198
- /* the value */
199
- yajl_encode_part(w, rb_hash_aref(obj, entry), io);
200
- }
224
+ struct yajl_encode_hash_iter iter;
225
+ iter.w = w;
226
+ iter.io = io;
227
+ rb_hash_foreach(obj, yajl_encode_part_hash_i, (VALUE)&iter);
201
228
 
202
229
  CHECK_STATUS(yajl_gen_map_close(w->encoder));
203
230
  break;
204
231
  case T_ARRAY:
205
232
  CHECK_STATUS(yajl_gen_array_open(w->encoder));
233
+
234
+ VALUE *ptr = RARRAY_PTR(obj);
206
235
  for(idx=0; idx<RARRAY_LEN(obj); idx++) {
207
- otherObj = rb_ary_entry(obj, idx);
208
- yajl_encode_part(w, otherObj, io);
236
+ yajl_encode_part(w, ptr[idx], io);
209
237
  }
210
238
  CHECK_STATUS(yajl_gen_array_close(w->encoder));
211
239
  break;
@@ -219,6 +247,8 @@ void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) {
219
247
  CHECK_STATUS(yajl_gen_bool(w->encoder, 0));
220
248
  break;
221
249
  case T_FIXNUM:
250
+ CHECK_STATUS(yajl_gen_long(w->encoder, FIX2LONG(obj)));
251
+ break;
222
252
  case T_FLOAT:
223
253
  case T_BIGNUM:
224
254
  str = rb_funcall(obj, intern_to_s, 0);
@@ -234,6 +264,12 @@ void yajl_encode_part(void * wrapper, VALUE obj, VALUE io) {
234
264
  len = (unsigned int)RSTRING_LEN(obj);
235
265
  CHECK_STATUS(yajl_gen_string(w->encoder, (const unsigned char *)cptr, len));
236
266
  break;
267
+ case T_SYMBOL:
268
+ str = rb_sym2str(obj);
269
+ cptr = RSTRING_PTR(str);
270
+ len = (unsigned int)RSTRING_LEN(str);
271
+ CHECK_STATUS(yajl_gen_string(w->encoder, (const unsigned char *)cptr, len));
272
+ break;
237
273
  default:
238
274
  if (rb_respond_to(obj, intern_to_json)) {
239
275
  str = rb_funcall(obj, intern_to_json, 0);
@@ -278,11 +314,17 @@ void yajl_parse_chunk(const unsigned char * chunk, unsigned int len, yajl_handle
278
314
 
279
315
  stat = yajl_parse(parser, chunk, len);
280
316
 
281
- if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
317
+ if (stat == yajl_status_ok || stat == yajl_status_insufficient_data) {
318
+ // success
319
+ } else if (stat == yajl_status_error) {
282
320
  unsigned char * str = yajl_get_error(parser, 1, chunk, len);
283
321
  VALUE errobj = rb_exc_new2(cParseError, (const char*) str);
284
322
  yajl_free_error(parser, str);
285
323
  rb_exc_raise(errobj);
324
+ } else {
325
+ const char * str = yajl_status_to_string(stat);
326
+ VALUE errobj = rb_exc_new2(cParseError, (const char*) str);
327
+ rb_exc_raise(errobj);
286
328
  }
287
329
  }
288
330
 
@@ -475,13 +517,13 @@ static VALUE rb_yajl_parser_init(int argc, VALUE * argv, VALUE self) {
475
517
  * Document-method: parse
476
518
  *
477
519
  * call-seq:
478
- * parse(input, buffer_size=8092)
479
- * parse(input, buffer_size=8092) { |obj| ... }
520
+ * parse(input, buffer_size=8192)
521
+ * parse(input, buffer_size=8192) { |obj| ... }
480
522
  *
481
523
  * +input+ can either be a string or an IO to parse JSON from
482
524
  *
483
525
  * +buffer_size+ is the size of chunk that will be parsed off the input (if it's an IO) for each loop of the parsing process.
484
- * 8092 is a good balance between the different types of streams (off disk, off a socket, etc...), but this option
526
+ * 8192 is a good balance between the different types of streams (off disk, off a socket, etc...), but this option
485
527
  * is here so the caller can better tune their parsing depending on the type of stream being passed.
486
528
  * A larger read buffer will perform better for files off disk, where as a smaller size may be more efficient for
487
529
  * reading off of a socket directly.
@@ -847,7 +889,7 @@ static VALUE rb_yajl_projector_build_simple_value(yajl_event_stream_t parser, ya
847
889
  case yajl_tok_bool:;
848
890
  if (memcmp(event.buf, "true", 4) == 0) {
849
891
  return Qtrue;
850
- } else if (memcmp(event.buf, "false", 4) == 0) {
892
+ } else if (memcmp(event.buf, "false", 5) == 0) {
851
893
  return Qfalse;
852
894
  } else {
853
895
  rb_raise(cStandardError, "unknown boolean token %s", event.buf);
@@ -884,7 +926,7 @@ static VALUE rb_yajl_projector_build_simple_value(yajl_event_stream_t parser, ya
884
926
  rb_raise(cParseError, "unexpected colon while constructing value");
885
927
 
886
928
  default:;
887
- assert(0);
929
+ rb_bug("we should never get here");
888
930
  }
889
931
  }
890
932
 
@@ -907,6 +949,9 @@ static VALUE rb_yajl_projector_build_string(yajl_event_stream_t parser, yajl_eve
907
949
 
908
950
  yajl_buf strBuf = yajl_buf_alloc(parser->funcs);
909
951
  yajl_string_decode(strBuf, (const unsigned char *)event.buf, event.len);
952
+ if (yajl_buf_err(strBuf)) {
953
+ rb_raise(cParseError, "YAJL internal error: failed to allocate memory");
954
+ }
910
955
 
911
956
  VALUE str = rb_str_new((const char *)yajl_buf_data(strBuf), yajl_buf_len(strBuf));
912
957
  rb_enc_associate(str, utf8Encoding);
@@ -922,7 +967,7 @@ static VALUE rb_yajl_projector_build_string(yajl_event_stream_t parser, yajl_eve
922
967
  }
923
968
 
924
969
  default:; {
925
- assert(0);
970
+ rb_bug("we should never get here");
926
971
  }
927
972
  }
928
973
  }
@@ -1102,6 +1147,7 @@ static VALUE rb_yajl_encoder_encode(int argc, VALUE * argv, VALUE self) {
1102
1147
  const unsigned char * buffer;
1103
1148
  unsigned int len;
1104
1149
  VALUE obj, io, blk, outBuff;
1150
+ yajl_gen_status status;
1105
1151
 
1106
1152
  GetEncoder(self, wrapper);
1107
1153
 
@@ -1115,7 +1161,11 @@ static VALUE rb_yajl_encoder_encode(int argc, VALUE * argv, VALUE self) {
1115
1161
  yajl_encode_part(wrapper, obj, io);
1116
1162
 
1117
1163
  /* just make sure we output the remaining buffer */
1118
- yajl_gen_get_buf(wrapper->encoder, &buffer, &len);
1164
+ status = yajl_gen_get_buf(wrapper->encoder, &buffer, &len);
1165
+ if (status != yajl_gen_status_ok) {
1166
+ yajl_raise_encode_error_for_status(status, obj);
1167
+ }
1168
+
1119
1169
  outBuff = rb_str_new((const char *)buffer, len);
1120
1170
  #ifdef HAVE_RUBY_ENCODING_H
1121
1171
  rb_enc_associate(outBuff, utf8Encoding);
data/ext/yajl/yajl_gen.c CHANGED
@@ -178,7 +178,7 @@ yajl_gen_free(yajl_gen g)
178
178
  if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
179
179
 
180
180
  #define DECREMENT_DEPTH \
181
- if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_gen_error;
181
+ if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_depth_underflow;
182
182
 
183
183
  #define APPENDED_ATOM \
184
184
  switch (g->state[g->depth]) { \
@@ -230,6 +230,36 @@ yajl_gen_double(yajl_gen g, double number)
230
230
  return yajl_gen_status_ok;
231
231
  }
232
232
 
233
+ yajl_gen_status
234
+ yajl_gen_long(yajl_gen g, long val)
235
+ {
236
+ char buf[32], *b = buf + sizeof buf;
237
+ unsigned int len = 0;
238
+ unsigned long uval;
239
+
240
+ ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
241
+
242
+ if (val < 0) {
243
+ g->print(g->ctx, "-", 1);
244
+ // Avoid overflow. This shouldn't happen because FIXNUMs are 1 bit less
245
+ // than LONGs, but good to be safe.
246
+ uval = 1 + (unsigned long)(-(val + 1));
247
+ } else {
248
+ uval = val;
249
+ }
250
+
251
+ do {
252
+ *--b = "0123456789"[uval % 10];
253
+ uval /= 10;
254
+ len++;
255
+ } while(uval);
256
+ g->print(g->ctx, b, len);
257
+
258
+ APPENDED_ATOM;
259
+ FINAL_NEWLINE;
260
+ return yajl_gen_status_ok;
261
+ }
262
+
233
263
  yajl_gen_status
234
264
  yajl_gen_number(yajl_gen g, const char * s, unsigned int l)
235
265
  {
@@ -332,6 +362,10 @@ yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
332
362
  unsigned int * len)
333
363
  {
334
364
  if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf;
365
+ yajl_buf_state buf_err = yajl_buf_err((yajl_buf)g->ctx);
366
+ if (buf_err) {
367
+ return yajl_gen_alloc_error;
368
+ }
335
369
  *buf = yajl_buf_data((yajl_buf)g->ctx);
336
370
  *len = yajl_buf_len((yajl_buf)g->ctx);
337
371
  return yajl_gen_status_ok;
data/ext/yajl/yajl_lex.c CHANGED
@@ -43,6 +43,7 @@ const char *yajl_tok_name(yajl_tok tok) {
43
43
  case yajl_tok_bool: return "bool";
44
44
  case yajl_tok_colon: return "colon";
45
45
  case yajl_tok_comma: return "comma";
46
+ case yajl_tok_comment: return "comment";
46
47
  case yajl_tok_eof: return "eof";
47
48
  case yajl_tok_error: return "error";
48
49
  case yajl_tok_left_brace: return "open_array";
@@ -117,6 +118,8 @@ yajl_lex_alloc(yajl_alloc_funcs * alloc,
117
118
  unsigned int allowComments, unsigned int validateUTF8)
118
119
  {
119
120
  yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
121
+ if (!lxr)
122
+ return NULL;
120
123
  memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
121
124
  lxr->buf = yajl_buf_alloc(alloc);
122
125
  lxr->allowComments = allowComments;
@@ -632,7 +635,12 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
632
635
  lexer->bufInUse = 1;
633
636
  yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
634
637
  lexer->bufOff = 0;
635
-
638
+
639
+ if (yajl_buf_err(lexer->buf)) {
640
+ lexer->error = yajl_lex_alloc_failed;
641
+ return yajl_tok_error;
642
+ }
643
+
636
644
  if (tok != yajl_tok_eof) {
637
645
  *outBuf = yajl_buf_data(lexer->buf);
638
646
  *outLen = yajl_buf_len(lexer->buf);
@@ -699,6 +707,8 @@ yajl_lex_error_to_string(yajl_lex_error error)
699
707
  case yajl_lex_unallowed_comment:
700
708
  return "probable comment found in input text, comments are "
701
709
  "not enabled.";
710
+ case yajl_lex_alloc_failed:
711
+ return "allocation failed";
702
712
  }
703
713
  return "unknown error code";
704
714
  }
data/ext/yajl/yajl_lex.h CHANGED
@@ -120,7 +120,8 @@ typedef enum {
120
120
  yajl_lex_missing_integer_after_decimal,
121
121
  yajl_lex_missing_integer_after_exponent,
122
122
  yajl_lex_missing_integer_after_minus,
123
- yajl_lex_unallowed_comment
123
+ yajl_lex_unallowed_comment,
124
+ yajl_lex_alloc_failed
124
125
  } yajl_lex_error;
125
126
 
126
127
  YAJL_API
@@ -134,6 +134,14 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
134
134
  return yajl_status_client_canceled; \
135
135
  }
136
136
 
137
+ /* check for buffer error */
138
+ #define _BUF_CHK(x) \
139
+ if (yajl_buf_err(x)) { \
140
+ yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
141
+ hand->parseError = \
142
+ "allocation failed"; \
143
+ return yajl_status_alloc_failed; \
144
+ }
137
145
 
138
146
  yajl_status
139
147
  yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
@@ -161,7 +169,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
161
169
  /* for arrays and maps, we advance the state for this
162
170
  * depth, then push the state of the next depth.
163
171
  * If an error occurs during the parsing of the nesting
164
- * enitity, the state at this level will not matter.
172
+ * entity, the state at this level will not matter.
165
173
  * a state that needs pushing will be anything other
166
174
  * than state_start */
167
175
  yajl_state stateToPush = yajl_state_start;
@@ -185,6 +193,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
185
193
  if (hand->callbacks && hand->callbacks->yajl_string) {
186
194
  yajl_buf_clear(hand->decodeBuf);
187
195
  yajl_string_decode(hand->decodeBuf, buf, bufLen);
196
+ _BUF_CHK(hand->decodeBuf);
188
197
  _CC_CHK(hand->callbacks->yajl_string(
189
198
  hand->ctx, yajl_buf_data(hand->decodeBuf),
190
199
  yajl_buf_len(hand->decodeBuf)));
@@ -234,6 +243,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
234
243
  long int i = 0;
235
244
  yajl_buf_clear(hand->decodeBuf);
236
245
  yajl_buf_append(hand->decodeBuf, buf, bufLen);
246
+ _BUF_CHK(hand->decodeBuf);
237
247
  buf = yajl_buf_data(hand->decodeBuf);
238
248
  i = strtol((const char *) buf, NULL, 10);
239
249
  if ((i == LONG_MIN || i == LONG_MAX) &&
@@ -261,6 +271,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
261
271
  double d = 0.0;
262
272
  yajl_buf_clear(hand->decodeBuf);
263
273
  yajl_buf_append(hand->decodeBuf, buf, bufLen);
274
+ _BUF_CHK(hand->decodeBuf);
264
275
  buf = yajl_buf_data(hand->decodeBuf);
265
276
  d = strtod((char *) buf, NULL);
266
277
  if ((d == HUGE_VAL || d == -HUGE_VAL) &&
@@ -320,7 +331,9 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
320
331
  }
321
332
  }
322
333
  if (stateToPush != yajl_state_start) {
323
- yajl_bs_push(hand->stateStack, stateToPush);
334
+ if (yajl_bs_push(hand->stateStack, stateToPush)) {
335
+ return yajl_status_alloc_failed;
336
+ }
324
337
  }
325
338
 
326
339
  goto around_again;
@@ -342,6 +355,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
342
355
  if (hand->callbacks && hand->callbacks->yajl_map_key) {
343
356
  yajl_buf_clear(hand->decodeBuf);
344
357
  yajl_string_decode(hand->decodeBuf, buf, bufLen);
358
+ _BUF_CHK(hand->decodeBuf);
345
359
  buf = yajl_buf_data(hand->decodeBuf);
346
360
  bufLen = yajl_buf_len(hand->decodeBuf);
347
361
  }
data/lib/yajl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yajl
2
- VERSION = '1.4.1'
2
+ VERSION = '1.4.2'
3
3
  end
@@ -230,6 +230,16 @@ describe "Yajl JSON encoder" do
230
230
  expect(s.read).to eql("{\"foo\":\"bar\"}")
231
231
  end
232
232
 
233
+ it "should encode all integers correctly" do
234
+ 0.upto(129).each do |b|
235
+ b = 1 << b
236
+ [b, b-1, b-2, b+1, b+2].each do |i|
237
+ expect(Yajl::Encoder.encode(i)).to eq(i.to_s)
238
+ expect(Yajl::Encoder.encode(-i)).to eq((-i).to_s)
239
+ end
240
+ end
241
+ end
242
+
233
243
  it "should not encode NaN" do
234
244
  expect {
235
245
  Yajl::Encoder.encode(0.0/0.0)
data/yajl-ruby.gemspec CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |s|
14
14
  s.rubygems_version = %q{1.4.2}
15
15
  s.summary = %q{Ruby C bindings to the excellent Yajl JSON stream-based parser library.}
16
16
  s.test_files = `git ls-files spec examples`.split("\n")
17
- s.required_ruby_version = ">= 1.8.6"
17
+ s.required_ruby_version = ">= 2.6.0"
18
18
 
19
19
  # tests
20
20
  s.add_development_dependency 'rake-compiler'
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yajl-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Lopez
8
8
  - Lloyd Hilaiel
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-07-27 00:00:00.000000000 Z
12
+ date: 2022-04-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
@@ -81,7 +81,7 @@ dependencies:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
- description:
84
+ description:
85
85
  email: seniorlopez@gmail.com
86
86
  executables: []
87
87
  extensions:
@@ -89,9 +89,9 @@ extensions:
89
89
  extra_rdoc_files: []
90
90
  files:
91
91
  - ".codeclimate.yml"
92
+ - ".github/workflows/ci.yml"
92
93
  - ".gitignore"
93
94
  - ".rspec"
94
- - ".travis.yml"
95
95
  - CHANGELOG.md
96
96
  - Gemfile
97
97
  - LICENSE
@@ -246,7 +246,7 @@ homepage: http://github.com/brianmario/yajl-ruby
246
246
  licenses:
247
247
  - MIT
248
248
  metadata: {}
249
- post_install_message:
249
+ post_install_message:
250
250
  rdoc_options: []
251
251
  require_paths:
252
252
  - lib
@@ -254,16 +254,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
254
254
  requirements:
255
255
  - - ">="
256
256
  - !ruby/object:Gem::Version
257
- version: 1.8.6
257
+ version: 2.6.0
258
258
  required_rubygems_version: !ruby/object:Gem::Requirement
259
259
  requirements:
260
260
  - - ">="
261
261
  - !ruby/object:Gem::Version
262
262
  version: '0'
263
263
  requirements: []
264
- rubyforge_project:
265
- rubygems_version: 2.6.11
266
- signing_key:
264
+ rubygems_version: 3.3.3
265
+ signing_key:
267
266
  specification_version: 4
268
267
  summary: Ruby C bindings to the excellent Yajl JSON stream-based parser library.
269
268
  test_files:
data/.travis.yml DELETED
@@ -1,9 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.0.0
4
- - 2.1
5
- - 2.2
6
- - 2.3
7
- - 2.4.1
8
- - ruby-head
9
- before_install: gem install bundler --no-document