json 2.7.6 → 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: 065f3d9d7ea71adff1e29821c3cac1ebcab3ab3fa8ffc5254d4977c61b998fd4
4
- data.tar.gz: d0ec44d829e429395f42191ac8bf91e6be4498e3c4bba37eb7fdf3ad1cfce80f
3
+ metadata.gz: 39c161c94f7ae85545dc117ec7616aa65f69e9192f081dd1d0934fc57f7a1b9b
4
+ data.tar.gz: f980984efc78b2bf8b0aa81e67dc8115e503bcb03171ce7658bdc9ba653da0b7
5
5
  SHA512:
6
- metadata.gz: 59f4e6204591c6fa2204e30ae4e663f5d5f6d89cfc44a26174da1a17cd720cd6594ad047b98933295a33f793b89e97c7952095bedda1d25f378b7a99ead84b04
7
- data.tar.gz: 7438175fc69f92a7aa2a13b7599b417111562d9edfd94987dec4f94c37e5f2b152a6025d2f6ed2d49d246f0b0e3fe53a71038c9c59e7f826e8d3c2e09e40994a
6
+ metadata.gz: 02e0733a4e893e0c486bc3ea2785c15601c5e660d990c8c83543df3df6f93acdb41d29e656f951896de8854f9672d89bae462f7761746e27614e038b48f72296
7
+ data.tar.gz: 5b22f7e7aa15e8965293fb91ac5d45631f5ef16dbaf0911f5d0763175138dfde8bb104dcea2df73c5e99fda45aecde081c971ccd2bc7c2dae9b4d700376ef8e3
data/CHANGES.md CHANGED
@@ -1,5 +1,20 @@
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
+
3
18
  ### 2024-11-04 (2.7.6)
4
19
 
5
20
  * Fix a regression in JSON.generate when dealing with Hash keys that are string subclasses, call `to_json` on them.
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,33 +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
- #ifndef RB_LIKELY
40
- #define RB_LIKELY(expr) expr
41
- #endif
42
-
43
- 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)
44
73
  {
45
- FBuffer *fb;
46
- if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
47
- fb = ALLOC(FBuffer);
48
- memset((void *) fb, 0, sizeof(FBuffer));
49
- fb->initial_length = initial_length;
50
- 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
+ }
51
80
  }
52
81
 
53
82
  static void fbuffer_free(FBuffer *fb)
54
83
  {
55
- if (fb->ptr) ruby_xfree(fb->ptr);
56
- ruby_xfree(fb);
84
+ if (fb->ptr && fb->type == FBUFFER_HEAP_ALLOCATED) {
85
+ ruby_xfree(fb->ptr);
86
+ }
57
87
  }
58
88
 
59
89
  #ifndef JSON_GENERATOR
@@ -63,22 +93,34 @@ static void fbuffer_clear(FBuffer *fb)
63
93
  }
64
94
  #endif
65
95
 
66
- static inline void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
96
+ static void fbuffer_do_inc_capa(FBuffer *fb, unsigned long requested)
67
97
  {
68
- if (RB_UNLIKELY(requested > fb->capa - fb->len)) {
69
- unsigned long required;
98
+ unsigned long required;
70
99
 
71
- if (RB_UNLIKELY(!fb->ptr)) {
72
- fb->ptr = ALLOC_N(char, fb->initial_length);
73
- fb->capa = fb->initial_length;
74
- }
100
+ if (RB_UNLIKELY(!fb->ptr)) {
101
+ fb->ptr = ALLOC_N(char, fb->initial_length);
102
+ fb->capa = fb->initial_length;
103
+ }
75
104
 
76
- for (required = fb->capa; requested > required - fb->len; required <<= 1);
105
+ for (required = fb->capa; requested > required - fb->len; required <<= 1);
77
106
 
78
- 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 {
79
114
  REALLOC_N(fb->ptr, char, required);
80
- fb->capa = required;
81
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);
82
124
  }
83
125
  }
84
126
 
@@ -103,7 +145,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
103
145
  }
104
146
  #endif
105
147
 
106
- static void fbuffer_append_char(FBuffer *fb, char newchr)
148
+ static inline void fbuffer_append_char(FBuffer *fb, char newchr)
107
149
  {
108
150
  fbuffer_inc_capa(fb, 1);
109
151
  *(fb->ptr + fb->len) = newchr;
@@ -111,33 +153,25 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
111
153
  }
112
154
 
113
155
  #ifdef JSON_GENERATOR
114
- static void freverse(char *start, char *end)
115
- {
116
- char c;
117
-
118
- while (end > start) {
119
- c = *end, *end-- = *start, *start++ = c;
120
- }
121
- }
122
-
123
156
  static long fltoa(long number, char *buf)
124
157
  {
125
- static char digits[] = "0123456789";
158
+ static const char digits[] = "0123456789";
126
159
  long sign = number;
127
160
  char* tmp = buf;
128
161
 
129
162
  if (sign < 0) number = -number;
130
- do *tmp++ = digits[number % 10]; while (number /= 10);
131
- if (sign < 0) *tmp++ = '-';
132
- freverse(buf, tmp - 1);
133
- return tmp - buf;
163
+ do *tmp-- = digits[number % 10]; while (number /= 10);
164
+ if (sign < 0) *tmp-- = '-';
165
+ return buf - tmp;
134
166
  }
135
167
 
168
+ #define LONG_BUFFER_SIZE 20
136
169
  static void fbuffer_append_long(FBuffer *fb, long number)
137
170
  {
138
- char buf[20];
139
- unsigned long len = fltoa(number, buf);
140
- 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);
141
175
  }
142
176
 
143
177
  static VALUE fbuffer_to_s(FBuffer *fb)