json 2.7.4 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c75f2746cbbd315a24997d2bf37e0284a9b21a99d43d7a5abf35369415f9ed9f
4
- data.tar.gz: 57c78c979d0aad97c7d8a7d8602ea7c47824f1a62f8335681ea2803a62b09fba
3
+ metadata.gz: 39c161c94f7ae85545dc117ec7616aa65f69e9192f081dd1d0934fc57f7a1b9b
4
+ data.tar.gz: f980984efc78b2bf8b0aa81e67dc8115e503bcb03171ce7658bdc9ba653da0b7
5
5
  SHA512:
6
- metadata.gz: 1fb3fc2fe76bbcdde8f1dd6a501e8868c0cc8be64a59841ef3ffe436e1b8f99fbc0a4fe383c200531a722c21097f9c925d71fba1320c0d181abe45c6f7c74291
7
- data.tar.gz: 739a9039ed42e1ddb4a5ca37a96e23485bc3383bd11c557f83bc63df16e0366bdc15cca886ffa041f3cb46a87010dd69657c2df54eefaa89597a8a4b8c6ff6bd
6
+ metadata.gz: 02e0733a4e893e0c486bc3ea2785c15601c5e660d990c8c83543df3df6f93acdb41d29e656f951896de8854f9672d89bae462f7761746e27614e038b48f72296
7
+ data.tar.gz: 5b22f7e7aa15e8965293fb91ac5d45631f5ef16dbaf0911f5d0763175138dfde8bb104dcea2df73c5e99fda45aecde081c971ccd2bc7c2dae9b4d700376ef8e3
data/CHANGES.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # Changes
2
2
 
3
+ ### 2024-11-06 (2.8.1)
4
+
5
+ * Fix the java packages to include the extension.
6
+
7
+ ### 2024-11-06 (2.8.0)
8
+
9
+ * Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled.
10
+ * Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`.
11
+ * Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`.
12
+ * Bump required Ruby version to 2.7.
13
+ * Add support for optionally parsing trailing commas, via `allow_trailing_comma: true`, which in cunjunction with the
14
+ pre-existing support for comments, make it suitable to parse `jsonc` documents.
15
+ * Many performance improvements to `JSON.parse` and `JSON.load`, up to `1.7x` faster on real world documents.
16
+ * Some minor performance improvements to `JSON.dump` and `JSON.generate`.
17
+
18
+ ### 2024-11-04 (2.7.6)
19
+
20
+ * Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them.
21
+
22
+ ### 2024-10-25 (2.7.5)
23
+
24
+ * Fix a memory leak when `#to_json` methods raise an exception.
25
+ * Gracefully handle formatting configs being set to `nil` instead of `""`.
26
+ * Workaround another issue caused by conflicting versions of both `json_pure` and `json` being loaded.
27
+
3
28
  ### 2024-10-25 (2.7.4)
4
29
 
5
30
  * Workaround a bug in 3.4.8 and older https://github.com/rubygems/rubygems/pull/6490.
data/README.md CHANGED
@@ -5,16 +5,10 @@
5
5
  ## Description
6
6
 
7
7
  This is an implementation of the JSON specification according to RFC 7159
8
- http://www.ietf.org/rfc/rfc7159.txt . There is two variants available:
8
+ http://www.ietf.org/rfc/rfc7159.txt .
9
9
 
10
- * A pure ruby variant, that relies on the `strscan` extensions, which is
11
- part of the ruby standard library.
12
- * The quite a bit faster native extension variant, which is in parts
13
- implemented in C or Java and comes with a parser generated by the [Ragel]
14
- state machine compiler.
15
-
16
- Both variants of the JSON generator generate UTF-8 character sequences by
17
- default. If an :ascii\_only option with a true value is given, they escape all
10
+ The JSON generator generate UTF-8 character sequences by default.
11
+ If an :ascii\_only option with a true value is given, they escape all
18
12
  non-ASCII and control characters with \uXXXX escape sequences, and support
19
13
  UTF-16 surrogate pairs in order to be able to generate the whole range of
20
14
  unicode code points.
@@ -27,10 +21,6 @@ endpoint.
27
21
 
28
22
  ## Installation
29
23
 
30
- It's recommended to use the extension variant of JSON, because it's faster than
31
- the pure ruby variant. If you cannot build it on your system, you can settle
32
- for the latter.
33
-
34
24
  Install the gem and add to the application's Gemfile by executing:
35
25
 
36
26
  $ bundle add json
@@ -39,12 +29,6 @@ If bundler is not being used to manage dependencies, install the gem by executin
39
29
 
40
30
  $ gem install json
41
31
 
42
-
43
- There is also a pure ruby json only variant of the gem, that can be installed
44
- with:
45
-
46
- $ gem install json_pure
47
-
48
32
  ## Usage
49
33
 
50
34
  To use JSON you can
@@ -53,20 +37,6 @@ To use JSON you can
53
37
  require 'json'
54
38
  ```
55
39
 
56
- to load the installed variant (either the extension `'json'` or the pure
57
- variant `'json_pure'`). If you have installed the extension variant, you can
58
- pick either the extension variant or the pure variant by typing
59
-
60
- ```ruby
61
- require 'json/ext'
62
- ```
63
-
64
- or
65
-
66
- ```ruby
67
- require 'json/pure'
68
- ```
69
-
70
40
  Now you can parse a JSON document into a ruby data structure by calling
71
41
 
72
42
  ```ruby
@@ -82,50 +52,11 @@ You can also use the `pretty_generate` method (which formats the output more
82
52
  verbosely and nicely) or `fast_generate` (which doesn't do any of the security
83
53
  checks generate performs, e. g. nesting deepness checks).
84
54
 
85
- There are also the JSON and JSON[] methods which use parse on a String or
86
- generate a JSON document from an array or hash:
87
-
88
- ```ruby
89
- document = JSON 'test' => 23 # => "{\"test\":23}"
90
- document = JSON['test' => 23] # => "{\"test\":23}"
91
- ```
92
-
93
- and
94
-
95
- ```ruby
96
- data = JSON '{"test":23}' # => {"test"=>23}
97
- data = JSON['{"test":23}'] # => {"test"=>23}
98
- ```
99
-
100
- You can choose to load a set of common additions to ruby core's objects if
101
- you
102
-
103
- ```ruby
104
- require 'json/add/core'
105
- ```
106
-
107
- After requiring this you can, e. g., serialise/deserialise Ruby ranges:
108
-
109
- ```ruby
110
- JSON JSON(1..10) # => 1..10
111
- ```
112
-
113
- To find out how to add JSON support to other or your own classes, read the
114
- section "More Examples" below.
115
-
116
- ## Serializing exceptions
117
-
118
- The JSON module doesn't extend `Exception` by default. If you convert an `Exception`
119
- object to JSON, it will by default only include the exception message.
120
-
121
- To include the full details, you must either load the `json/add/core` mentioned
122
- above, or specifically load the exception addition:
123
-
124
- ```ruby
125
- require 'json/add/exception'
126
- ```
55
+ ## Handling arbitrary types
127
56
 
128
- ## More Examples
57
+ > [!CAUTION]
58
+ > You should never use `JSON.unsafe_load` nor `JSON.parse(str, create_additions: true)` to parse untrusted user input,
59
+ > as it can lead to remote code execution vulnerabilities.
129
60
 
130
61
  To create a JSON document from a ruby data structure, you can call
131
62
  `JSON.generate` like that:
@@ -191,7 +122,7 @@ JSON.parse json
191
122
  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
192
123
  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
193
124
  # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
194
- JSON.parse json, :create_additions => true
125
+ JSON.unsafe_load json
195
126
  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
196
127
  ```
197
128
 
@@ -4,21 +4,58 @@
4
4
  #include "ruby.h"
5
5
  #include "ruby/encoding.h"
6
6
 
7
+ /* shims */
8
+ /* This is the fallback definition from Ruby 3.4 */
9
+
10
+ #ifndef RBIMPL_STDBOOL_H
11
+ #if defined(__cplusplus)
12
+ # if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
13
+ # include <cstdbool>
14
+ # endif
15
+ #elif defined(HAVE_STDBOOL_H)
16
+ # include <stdbool.h>
17
+ #elif !defined(HAVE__BOOL)
18
+ typedef unsigned char _Bool;
19
+ # define bool _Bool
20
+ # define true ((_Bool)+1)
21
+ # define false ((_Bool)+0)
22
+ # define __bool_true_false_are_defined
23
+ #endif
24
+ #endif
25
+
26
+ #ifndef RB_UNLIKELY
27
+ #define RB_UNLIKELY(expr) expr
28
+ #endif
29
+
30
+ #ifndef RB_LIKELY
31
+ #define RB_LIKELY(expr) expr
32
+ #endif
33
+
34
+ #ifndef MAYBE_UNUSED
35
+ # define MAYBE_UNUSED(x) x
36
+ #endif
37
+
38
+ enum fbuffer_type {
39
+ FBUFFER_HEAP_ALLOCATED = 0,
40
+ FBUFFER_STACK_ALLOCATED = 1,
41
+ };
42
+
7
43
  typedef struct FBufferStruct {
44
+ enum fbuffer_type type;
8
45
  unsigned long initial_length;
9
- char *ptr;
10
46
  unsigned long len;
11
47
  unsigned long capa;
48
+ char *ptr;
12
49
  } FBuffer;
13
50
 
51
+ #define FBUFFER_STACK_SIZE 512
14
52
  #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
15
53
 
16
- #define FBUFFER_PTR(fb) (fb->ptr)
17
- #define FBUFFER_LEN(fb) (fb->len)
18
- #define FBUFFER_CAPA(fb) (fb->capa)
54
+ #define FBUFFER_PTR(fb) ((fb)->ptr)
55
+ #define FBUFFER_LEN(fb) ((fb)->len)
56
+ #define FBUFFER_CAPA(fb) ((fb)->capa)
19
57
  #define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
20
58
 
21
- static FBuffer *fbuffer_alloc(unsigned long initial_length);
22
59
  static void fbuffer_free(FBuffer *fb);
23
60
  #ifndef JSON_GENERATOR
24
61
  static void fbuffer_clear(FBuffer *fb);
@@ -27,29 +64,26 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
27
64
  #ifdef JSON_GENERATOR
28
65
  static void fbuffer_append_long(FBuffer *fb, long number);
29
66
  #endif
30
- static void fbuffer_append_char(FBuffer *fb, char newchr);
67
+ static inline void fbuffer_append_char(FBuffer *fb, char newchr);
31
68
  #ifdef JSON_GENERATOR
32
69
  static VALUE fbuffer_to_s(FBuffer *fb);
33
70
  #endif
34
71
 
35
- #ifndef RB_UNLIKELY
36
- #define RB_UNLIKELY(expr) expr
37
- #endif
38
-
39
- static FBuffer *fbuffer_alloc(unsigned long initial_length)
72
+ static void fbuffer_stack_init(FBuffer *fb, unsigned long initial_length, char *stack_buffer, long stack_buffer_size)
40
73
  {
41
- FBuffer *fb;
42
- if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
43
- fb = ALLOC(FBuffer);
44
- memset((void *) fb, 0, sizeof(FBuffer));
45
- fb->initial_length = initial_length;
46
- return fb;
74
+ fb->initial_length = (initial_length > 0) ? initial_length : FBUFFER_INITIAL_LENGTH_DEFAULT;
75
+ if (stack_buffer) {
76
+ fb->type = FBUFFER_STACK_ALLOCATED;
77
+ fb->ptr = stack_buffer;
78
+ fb->capa = stack_buffer_size;
79
+ }
47
80
  }
48
81
 
49
82
  static void fbuffer_free(FBuffer *fb)
50
83
  {
51
- if (fb->ptr) ruby_xfree(fb->ptr);
52
- ruby_xfree(fb);
84
+ if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
85
+ ruby_xfree(fb->ptr);
86
+ }
53
87
  }
54
88
 
55
89
  #ifndef JSON_GENERATOR
@@ -59,22 +93,34 @@ static void fbuffer_clear(FBuffer *fb)
59
93
  }
60
94
  #endif
61
95
 
62
- static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
96
+ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
63
97
  {
64
- if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
65
- unsigned long required;
98
+ unsigned long required;
66
99
 
67
- if (RB_UNLIKELY(!fb->ptr)) {
68
- fb->ptr = ALLOC_N(char, fb->initial_length);
69
- fb->capa = fb->initial_length;
70
- }
100
+ if (RB_UNLIKELY(!fb->ptr)) {
101
+ fb->ptr = ALLOC_N(char, fb->initial_length);
102
+ fb->capa = fb->initial_length;
103
+ }
71
104
 
72
- for (required = fb->capa; requested > required - fb->len; required <<= 1);
105
+ for (required = fb->capa; requested > required - fb->len; required <<= 1);
73
106
 
74
- if (required > fb->capa) {
107
+ if (required > fb->capa) {
108
+ if (fb->type == FBUFFER_STACK_ALLOCATED) {
109
+ const char *old_buffer = fb->ptr;
110
+ fb->ptr = ALLOC_N(char, required);
111
+ fb->type = FBUFFER_HEAP_ALLOCATED;
112
+ MEMCPY(fb->ptr, old_buffer, char, fb->len);
113
+ } else {
75
114
  REALLOC_N(fb->ptr, char, required);
76
- fb->capa = required;
77
115
  }
116
+ fb->capa = required;
117
+ }
118
+ }
119
+
120
+ static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
121
+ {
122
+ if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
123
+ fbuffer_do_inc_capa(fb, requested);
78
124
  }
79
125
  }
80
126
 
@@ -99,7 +145,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
99
145
  }
100
146
  #endif
101
147
 
102
- static void fbuffer_append_char(FBuffer *fb, char newchr)
148
+ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
103
149
  {
104
150
  fbuffer_inc_capa(fb, 1);
105
151
  *(fb->ptr + fb->len) = newchr;
@@ -107,33 +153,25 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
107
153
  }
108
154
 
109
155
  #ifdef JSON_GENERATOR
110
- static void freverse(char *start, char *end)
111
- {
112
- char c;
113
-
114
- while (end > start) {
115
- c = *end, *end-- = *start, *start++ = c;
116
- }
117
- }
118
-
119
156
  static long fltoa(long number, char *buf)
120
157
  {
121
- static char digits[] = "0123456789";
158
+ static const char digits[] = "0123456789";
122
159
  long sign = number;
123
160
  char* tmp = buf;
124
161
 
125
162
  if (sign < 0) number = -number;
126
- do *tmp++ = digits[number % 10]; while (number /= 10);
127
- if (sign < 0) *tmp++ = '-';
128
- freverse(buf, tmp - 1);
129
- return tmp - buf;
163
+ do *tmp-- = digits[number % 10]; while (number /= 10);
164
+ if (sign < 0) *tmp-- = '-';
165
+ return buf - tmp;
130
166
  }
131
167
 
168
+ #define LONG_BUFFER_SIZE 20
132
169
  static void fbuffer_append_long(FBuffer *fb, long number)
133
170
  {
134
- char buf[20];
135
- unsigned long len = fltoa(number, buf);
136
- fbuffer_append(fb, buf, len);
171
+ char buf[LONG_BUFFER_SIZE];
172
+ char *buffer_end = buf + LONG_BUFFER_SIZE;
173
+ long len = fltoa(number, buffer_end - 1);
174
+ fbuffer_append(fb, buffer_end - len, len);
137
175
  }
138
176
 
139
177
  static VALUE fbuffer_to_s(FBuffer *fb)