Skip to content

Commit

Permalink
Merge pull request #388 from flori/backport-ruby-core
Browse files Browse the repository at this point in the history
Backport ruby core changes
  • Loading branch information
hsbt committed Nov 29, 2019
2 parents 8d8e1aa + 5a28298 commit e5e9a77
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 35 deletions.
25 changes: 16 additions & 9 deletions ext/json/ext/generator/generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
#endif
mFloat, mString, mString_Extend,
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
eNestingError, CRegexp_MULTILINE, CJSON_SAFE_STATE_PROTOTYPE,
eNestingError,
i_SAFE_STATE_PROTOTYPE;

static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
Expand Down Expand Up @@ -696,7 +696,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
return rb_funcall(self, i_send, 1, name);
} else {
return rb_ivar_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
}
}

Expand Down Expand Up @@ -846,11 +846,20 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
fbuffer_append_char(buffer, ']');
}

#ifdef HAVE_RUBY_ENCODING_H
static int enc_utf8_compatible_p(rb_encoding *enc)
{
if (enc == rb_usascii_encoding()) return 1;
if (enc == rb_utf8_encoding()) return 1;
return 0;
}
#endif

static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
{
fbuffer_append_char(buffer, '"');
#ifdef HAVE_RUBY_ENCODING_H
if (!rb_enc_str_asciicompat_p(obj)) {
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
}
#endif
Expand Down Expand Up @@ -1073,10 +1082,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
return rb_funcall(self, i_new, 1, opts);
} else {
if (NIL_P(CJSON_SAFE_STATE_PROTOTYPE)) {
CJSON_SAFE_STATE_PROTOTYPE = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
}
return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
return rb_funcall(prototype, i_dup, 0);
}
}

Expand Down Expand Up @@ -1392,6 +1399,8 @@ void Init_generator(void)

eGeneratorError = rb_path2class("JSON::GeneratorError");
eNestingError = rb_path2class("JSON::NestingError");
rb_gc_register_mark_object(eGeneratorError);
rb_gc_register_mark_object(eNestingError);

cState = rb_define_class_under(mGenerator, "State", rb_cObject);
rb_define_alloc_func(cState, cState_s_allocate);
Expand Down Expand Up @@ -1457,7 +1466,6 @@ void Init_generator(void)
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);

CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
i_to_s = rb_intern("to_s");
i_to_json = rb_intern("to_json");
i_new = rb_intern("new");
Expand Down Expand Up @@ -1488,5 +1496,4 @@ void Init_generator(void)
i_encode = rb_intern("encode");
#endif
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
}
15 changes: 11 additions & 4 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

/* This file is automatically generated from parser.rl by using ragel */
#line 1 "parser.rl"
#include "../fbuffer/fbuffer.h"
#include "parser.h"
Expand Down Expand Up @@ -27,7 +27,7 @@ enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)

/* unicode */

static const char digit_values[256] = {
static const signed char digit_values[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
Expand All @@ -46,7 +46,7 @@ static const char digit_values[256] = {

static UTF32 unescape_unicode(const unsigned char *p)
{
char b;
signed char b;
UTF32 result = 0;
b = digit_values[p[0]];
if (b < 0) return UNI_REPLACEMENT_CHAR;
Expand Down Expand Up @@ -1833,7 +1833,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
} else {
json->max_nesting = 100;
json->allow_nan = 0;
json->create_additions = 1;
json->create_additions = 0;
json->create_id = rb_funcall(mJSON, i_create_id, 0);
json->object_class = Qnil;
json->array_class = Qnil;
Expand Down Expand Up @@ -2089,14 +2089,21 @@ void Init_parser(void)
cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
eParserError = rb_path2class("JSON::ParserError");
eNestingError = rb_path2class("JSON::NestingError");
rb_gc_register_mark_object(eParserError);
rb_gc_register_mark_object(eNestingError);
rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
rb_define_method(cParser, "initialize", cParser_initialize, -1);
rb_define_method(cParser, "parse", cParser_parse, 0);
rb_define_method(cParser, "source", cParser_source, 0);

CNaN = rb_const_get(mJSON, rb_intern("NaN"));
rb_gc_register_mark_object(CNaN);

CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
rb_gc_register_mark_object(CInfinity);

CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
rb_gc_register_mark_object(CMinusInfinity);

i_json_creatable_p = rb_intern("json_creatable?");
i_json_create = rb_intern("json_create");
Expand Down
13 changes: 10 additions & 3 deletions ext/json/ext/parser/parser.rl
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)

/* unicode */

static const char digit_values[256] = {
static const signed char digit_values[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
Expand All @@ -44,7 +44,7 @@ static const char digit_values[256] = {

static UTF32 unescape_unicode(const unsigned char *p)
{
char b;
signed char b;
UTF32 result = 0;
b = digit_values[p[0]];
if (b < 0) return UNI_REPLACEMENT_CHAR;
Expand Down Expand Up @@ -728,7 +728,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
} else {
json->max_nesting = 100;
json->allow_nan = 0;
json->create_additions = 1;
json->create_additions = 0;
json->create_id = rb_funcall(mJSON, i_create_id, 0);
json->object_class = Qnil;
json->array_class = Qnil;
Expand Down Expand Up @@ -849,14 +849,21 @@ void Init_parser(void)
cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
eParserError = rb_path2class("JSON::ParserError");
eNestingError = rb_path2class("JSON::NestingError");
rb_gc_register_mark_object(eParserError);
rb_gc_register_mark_object(eNestingError);
rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
rb_define_method(cParser, "initialize", cParser_initialize, -1);
rb_define_method(cParser, "parse", cParser_parse, 0);
rb_define_method(cParser, "source", cParser_source, 0);

CNaN = rb_const_get(mJSON, rb_intern("NaN"));
rb_gc_register_mark_object(CNaN);

CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
rb_gc_register_mark_object(CInfinity);

CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
rb_gc_register_mark_object(CMinusInfinity);

i_json_creatable_p = rb_intern("json_creatable?");
i_json_create = rb_intern("json_create");
Expand Down
Binary file modified json.gemspec
Binary file not shown.
4 changes: 2 additions & 2 deletions lib/json/common.rb
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class MissingUnicodeSupport < JSONError; end
# * *object_class*: Defaults to Hash
# * *array_class*: Defaults to Array
def parse(source, opts = {})
Parser.new(source, opts).parse
Parser.new(source, **(opts||{})).parse
end

# Parse the JSON document _source_ into a Ruby data structure and return it.
Expand All @@ -176,7 +176,7 @@ def parse!(source, opts = {})
:max_nesting => false,
:allow_nan => true
}.merge(opts)
Parser.new(source, opts).parse
Parser.new(source, **(opts||{})).parse
end

# Generate a JSON document from the Ruby data structure _obj_ and return
Expand Down
6 changes: 3 additions & 3 deletions tests/json_common_interface_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ def test_index
end

def test_parser
assert_match /::Parser\z/, JSON.parser.name
assert_match(/::Parser\z/, JSON.parser.name)
end

def test_generator
assert_match /::Generator\z/, JSON.generator.name
assert_match(/::Generator\z/, JSON.generator.name)
end

def test_state
assert_match /::Generator::State\z/, JSON.state.name
assert_match(/::Generator::State\z/, JSON.state.name)
end

def test_create_id
Expand Down
43 changes: 43 additions & 0 deletions tests/json_generator_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ def setup
EOT
end

def silence
v = $VERBOSE
$VERBOSE = nil
yield
ensure
$VERBOSE = v
end

def test_remove_const_segv
stress = GC.stress
const = JSON::SAFE_STATE_PROTOTYPE.dup

bignum_too_long_to_embed_as_string = 1234567890123456789012345
expect = bignum_too_long_to_embed_as_string.to_s
GC.stress = true

10.times do |i|
tmp = bignum_too_long_to_embed_as_string.to_json
raise "'\#{expect}' is expected, but '\#{tmp}'" unless tmp == expect
end

silence do
JSON.const_set :SAFE_STATE_PROTOTYPE, nil
end

10.times do |i|
assert_raise TypeError do
bignum_too_long_to_embed_as_string.to_json
end
end
ensure
GC.stress = stress
silence do
JSON.const_set :SAFE_STATE_PROTOTYPE, const
end
end if JSON.const_defined?("Ext")

def test_generate
json = generate(@hash)
assert_equal(parse(@json2), parse(json))
Expand Down Expand Up @@ -374,4 +411,10 @@ def to_s; self; end
assert_equal '["foo"]', JSON.generate([s.new('foo')])
end
end

if defined?(Encoding)
def test_nonutf8_encoding
assert_equal("\"5\u{b0}\"", "5\xb0".force_encoding("iso-8859-1").to_json)
end
end
end
28 changes: 14 additions & 14 deletions tests/json_parser_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,27 @@ def test_parse_numbers
assert_raise(JSON::ParserError) { parse('+23') }
assert_raise(JSON::ParserError) { parse('.23') }
assert_raise(JSON::ParserError) { parse('023') }
assert_equal 23, parse('23')
assert_equal -23, parse('-23')
assert_equal_float 3.141, parse('3.141')
assert_equal_float -3.141, parse('-3.141')
assert_equal_float 3.141, parse('3141e-3')
assert_equal_float 3.141, parse('3141.1e-3')
assert_equal_float 3.141, parse('3141E-3')
assert_equal_float 3.141, parse('3141.0E-3')
assert_equal_float -3.141, parse('-3141.0e-3')
assert_equal_float -3.141, parse('-3141e-3')
assert_equal(23, parse('23'))
assert_equal(-23, parse('-23'))
assert_equal_float(3.141, parse('3.141'))
assert_equal_float(-3.141, parse('-3.141'))
assert_equal_float(3.141, parse('3141e-3'))
assert_equal_float(3.141, parse('3141.1e-3'))
assert_equal_float(3.141, parse('3141E-3'))
assert_equal_float(3.141, parse('3141.0E-3'))
assert_equal_float(-3.141, parse('-3141.0e-3'))
assert_equal_float(-3.141, parse('-3141e-3'))
assert_raise(ParserError) { parse('NaN') }
assert parse('NaN', :allow_nan => true).nan?
assert_raise(ParserError) { parse('Infinity') }
assert_equal 1.0/0, parse('Infinity', :allow_nan => true)
assert_equal(1.0/0, parse('Infinity', :allow_nan => true))
assert_raise(ParserError) { parse('-Infinity') }
assert_equal -1.0/0, parse('-Infinity', :allow_nan => true)
assert_equal(-1.0/0, parse('-Infinity', :allow_nan => true))
end

def test_parse_bigdecimals
assert_equal(BigDecimal, JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"].class)
assert_equal(BigDecimal.new("0.901234567890123456789E1"),JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"] )
assert_equal(BigDecimal, JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"].class)
assert_equal(BigDecimal("0.901234567890123456789E1"),JSON.parse('{"foo": 9.01234567890123456789}', decimal_class: BigDecimal)["foo"] )
end

if Array.method_defined?(:permutation)
Expand Down

0 comments on commit e5e9a77

Please sign in to comment.