diff options
author | Joshua Haberman <jhaberman@gmail.com> | 2016-07-25 10:09:15 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-25 10:09:15 -0700 |
commit | 44bd6bda58d3889c06e82c5060609182f124aba3 (patch) | |
tree | facc0a600e9b52dc5c94d48f891c8c4a845eca67 /ruby/ext/google/protobuf_c/storage.c | |
parent | 06220303323f3cce425706540defcd7a29d42ec2 (diff) | |
parent | d07a9963df7c01d978c0749eb5753f98a3f0dc65 (diff) | |
download | protobuf-44bd6bda58d3889c06e82c5060609182f124aba3.tar.gz protobuf-44bd6bda58d3889c06e82c5060609182f124aba3.tar.bz2 protobuf-44bd6bda58d3889c06e82c5060609182f124aba3.zip |
Merge pull request #1821 from haberman/rubyfreezestr
Ruby: encode and freeze strings when the are assigned or decoded.
Diffstat (limited to 'ruby/ext/google/protobuf_c/storage.c')
-rw-r--r-- | ruby/ext/google/protobuf_c/storage.c | 39 |
1 files changed, 19 insertions, 20 deletions
diff --git a/ruby/ext/google/protobuf_c/storage.c b/ruby/ext/google/protobuf_c/storage.c index 1c839781..3ff2bda6 100644 --- a/ruby/ext/google/protobuf_c/storage.c +++ b/ruby/ext/google/protobuf_c/storage.c @@ -117,25 +117,24 @@ void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE val) { } } -void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value) { - bool bad_encoding = false; - rb_encoding* string_encoding = rb_enc_from_index(ENCODING_GET(value)); - if (type == UPB_TYPE_STRING) { - bad_encoding = - string_encoding != kRubyStringUtf8Encoding && - string_encoding != kRubyStringASCIIEncoding; - } else { - bad_encoding = - string_encoding != kRubyString8bitEncoding; - } - // Check that encoding is UTF-8 or ASCII (for string fields) or ASCII-8BIT - // (for bytes fields). - if (bad_encoding) { - rb_raise(rb_eTypeError, "Encoding for '%s' fields must be %s (was %s)", - (type == UPB_TYPE_STRING) ? "string" : "bytes", - (type == UPB_TYPE_STRING) ? "UTF-8 or ASCII" : "ASCII-8BIT", - rb_enc_name(string_encoding)); +VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value) { + rb_encoding* desired_encoding = (type == UPB_TYPE_STRING) ? + kRubyStringUtf8Encoding : kRubyString8bitEncoding; + VALUE desired_encoding_value = rb_enc_from_encoding(desired_encoding); + + // Note: this will not duplicate underlying string data unless necessary. + value = rb_str_encode(value, desired_encoding_value, 0, Qnil); + + if (type == UPB_TYPE_STRING && + rb_enc_str_coderange(value) == ENC_CODERANGE_BROKEN) { + rb_raise(rb_eEncodingError, "String is invalid UTF-8"); } + + // Ensure the data remains valid. Since we called #encode a moment ago, + // this does not freeze the string the user assigned. + rb_obj_freeze(value); + + return value; } void native_slot_set(upb_fieldtype_t type, VALUE type_class, @@ -181,8 +180,8 @@ void native_slot_set_value_and_case(upb_fieldtype_t type, VALUE type_class, if (CLASS_OF(value) != rb_cString) { rb_raise(rb_eTypeError, "Invalid argument for string field."); } - native_slot_validate_string_encoding(type, value); - DEREF(memory, VALUE) = value; + + DEREF(memory, VALUE) = native_slot_encode_and_freeze_string(type, value); break; } case UPB_TYPE_MESSAGE: { |