json 2.7.6 → 2.8.0.alpha1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 065f3d9d7ea71adff1e29821c3cac1ebcab3ab3fa8ffc5254d4977c61b998fd4
4
- data.tar.gz: d0ec44d829e429395f42191ac8bf91e6be4498e3c4bba37eb7fdf3ad1cfce80f
3
+ metadata.gz: e37f288be36138ec53fe36090c7886445f097184538b33b04ce12524082f6f8f
4
+ data.tar.gz: a7a4d1069d594d876cad44766c22ff3688f171b5cfa5ed636bec07daaae11b82
5
5
  SHA512:
6
- metadata.gz: 59f4e6204591c6fa2204e30ae4e663f5d5f6d89cfc44a26174da1a17cd720cd6594ad047b98933295a33f793b89e97c7952095bedda1d25f378b7a99ead84b04
7
- data.tar.gz: 7438175fc69f92a7aa2a13b7599b417111562d9edfd94987dec4f94c37e5f2b152a6025d2f6ed2d49d246f0b0e3fe53a71038c9c59e7f826e8d3c2e09e40994a
6
+ metadata.gz: 1025ceda0144fb3ead6b25813e994565c9fcd99573f04db11cee7fd7a8db1b7b362590d85db99176a6e0884f231e128b411f1f24f19aee77bd9413973cbcaf90
7
+ data.tar.gz: 8f8c78a0ef4fc3c1334318813d1ffa944f770f5a2fca17c4b23c7ad89a29fa6a17b47d1caf1b3615ecad23ee9a0af6f80d19a72b2228af80887a4f0f51c1eed3
data/CHANGES.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changes
2
2
 
3
+ ### UNRELEASED
4
+
5
+ * Emit a deprecation warning when `JSON.load` create custom types without the `create_additions` option being explictly enabled.
6
+ * Prefer to use `JSON.unsafe_load(string)` or `JSON.load(string, create_additions: true)`.
7
+ * Emit a deprecation warning when serializing valid UTF-8 strings encoded in `ASCII_8BIT` aka `BINARY`.
8
+ * Bump required_ruby_version to 2.7.
9
+ * More performance improvments to `JSON.dump` and `JSON.generate`.
10
+
3
11
  ### 2024-11-04 (2.7.6)
4
12
 
5
13
  * 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)