yajl-ruby 1.3.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: 2211f169082b89b1385a841f79d445cd559b405c
4
- data.tar.gz: 9074ca9bab2acf80a0a7069f2a608ee958b2eea8
2
+ SHA256:
3
+ metadata.gz: dcd3ae6509fd5f45b1527644b221e2ec44e4f697ef0ef5d92399aee3567ad7a6
4
+ data.tar.gz: 0045452d11da4b6b6fbcdf965fd94d0d43655245cb68fca518bfddc38513ad6c
5
5
  SHA512:
6
- metadata.gz: 20f296b807da6097dec709b153364def6cae62187223e64027871103261800e8edda82d5d2bfe96a9dbfb3e29a6b84f56e39c09b45d3bafd423335e86aa52186
7
- data.tar.gz: 89bee3f6029488f771d15a4ebc9e910a8c1ca7d276ef5ad001bb118e7754397bfb4a4065cf5a8b8cc5edffe222bdb669742b6cbe9c6572d3656b3d683393c2b8
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
@@ -1,7 +1,12 @@
1
1
  require 'mkmf'
2
2
  require 'rbconfig'
3
3
 
4
- $CFLAGS << ' -Wall -funroll-loops'
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
@@ -59,12 +59,18 @@ yajl_string_encode2(const yajl_print_t print,
59
59
  unsigned int htmlSafe)
60
60
  {
61
61
  unsigned int beg = 0;
62
- unsigned int end = 0;
62
+ unsigned int end = 0;
63
+ unsigned int increment = 0;
63
64
  char hexBuf[7];
65
+ char entityBuffer[7];
64
66
  hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
65
67
  hexBuf[6] = 0;
66
68
 
69
+ entityBuffer[0] = '\\'; entityBuffer[1] = 'u'; entityBuffer[2] = '2'; entityBuffer[3] = '0';
70
+ entityBuffer[6] = 0;
71
+
67
72
  while (end < len) {
73
+ increment = 1;
68
74
  const char * escaped = NULL;
69
75
  switch (str[end]) {
70
76
  case '\r': escaped = "\\r"; break;
@@ -76,10 +82,39 @@ yajl_string_encode2(const yajl_print_t print,
76
82
  case '\b': escaped = "\\b"; break;
77
83
  case '\t': escaped = "\\t"; break;
78
84
  case '/':
79
- if (htmlSafe) {
85
+ if (htmlSafe == 1 || htmlSafe == 2) {
80
86
  escaped = "\\/";
81
87
  }
82
88
  break;
89
+ /* Escaping 0xe280a8 0xe280a9 */
90
+ case 0xe2:
91
+ if (htmlSafe == 2) {
92
+ if (len - end >= 2 && str[end + 1] == 0x80) {
93
+ if (str[end + 2] == 0xa8) {
94
+ increment = 3;
95
+ entityBuffer[4] = '2';
96
+ entityBuffer[5] = '8';
97
+ escaped = entityBuffer;
98
+ break;
99
+ }
100
+
101
+ if (str[end + 2] == 0xa9) {
102
+ increment = 3;
103
+ entityBuffer[4] = '2';
104
+ entityBuffer[5] = '9';
105
+ escaped = entityBuffer;
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ case '<':
111
+ case '>':
112
+ case '&':
113
+ if (htmlSafe == 2) {
114
+ CharToHex(str[end], hexBuf + 4);
115
+ escaped = hexBuf;
116
+ }
117
+ break;
83
118
  default:
84
119
  if ((unsigned char) str[end] < 32) {
85
120
  CharToHex(str[end], hexBuf + 4);
@@ -90,7 +125,8 @@ yajl_string_encode2(const yajl_print_t print,
90
125
  if (escaped != NULL) {
91
126
  print(ctx, (const char *) (str + beg), end - beg);
92
127
  print(ctx, escaped, (unsigned int)strlen(escaped));
93
- beg = ++end;
128
+ end += increment;
129
+ beg = end;
94
130
  } else {
95
131
  ++end;
96
132
  }