diff options
-rw-r--r-- | .travis.yml | 21 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/encode_decode.c | 53 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/map.c | 20 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/protobuf.h | 3 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/repeated_field.c | 5 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/storage.c | 39 | ||||
-rw-r--r-- | ruby/ext/google/protobuf_c/upb.c | 2 | ||||
-rw-r--r-- | ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java | 4 | ||||
-rw-r--r-- | ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java | 4 | ||||
-rw-r--r-- | ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java | 4 | ||||
-rw-r--r-- | ruby/src/main/java/com/google/protobuf/jruby/Utils.java | 37 | ||||
-rw-r--r-- | ruby/tests/basic.rb | 44 | ||||
-rw-r--r-- | src/Makefile.am | 34 | ||||
-rw-r--r-- | src/google/protobuf/compiler/objectivec/objectivec_generator.cc | 25 | ||||
-rw-r--r-- | src/google/protobuf/map.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/repeated_field_reflection.h | 337 | ||||
-rw-r--r-- | src/google/protobuf/wire_format_lite_inl.h | 10 |
17 files changed, 190 insertions, 454 deletions
diff --git a/.travis.yml b/.travis.yml index 9d7e4c5b..1417cb98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ sudo: required # rvm/gemfile/jdk/etc. entries rather than manually doing the work. language: cpp os: - - linux - osx # The Objective C build needs Xcode 7.0 or later. osx_image: xcode7.3 @@ -47,23 +46,17 @@ matrix: # which doesn't work on OS X. - os: osx env: CONFIG=golang - # OS X/iOS tests of Objective C (needs Xcode, so it won't work on other - # platforms). - - os: linux - env: CONFIG=objectivec_ios_debug - - os: linux - env: CONFIG=objectivec_ios_release - - os: linux - env: CONFIG=objectivec_osx - - os: linux - env: CONFIG=objectivec_cocoapods_integration - # The dotnet environment requires Ubuntu 14.04 or 16.04. This - # configuration is effectively an "extra" one, outside the - # autogenerated matrix. include: + # The dotnet environment requires Ubuntu 14.04 or 16.04. This + # configuration is effectively an "extra" one, outside the + # autogenerated matrix. - os: linux env: CONFIG=csharp dist: trusty + # This test is kept on travis because it doesn't play nicely with other + # tests on jenkins running in parallel. + - os: linux + env: CONFIG=cpp_distcheck allow_failures: # These currently do not work on OS X but are being worked on by @haberman. - os: osx diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index f6bea50f..dd21a046 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -54,7 +54,7 @@ VALUE noleak_rb_str_cat(VALUE rb_str, const char *str, long len) { static const void* newhandlerdata(upb_handlers* h, uint32_t ofs) { size_t* hd_ofs = ALLOC(size_t); *hd_ofs = ofs; - upb_handlers_addcleanup(h, hd_ofs, free); + upb_handlers_addcleanup(h, hd_ofs, xfree); return hd_ofs; } @@ -69,7 +69,7 @@ static const void *newsubmsghandlerdata(upb_handlers* h, uint32_t ofs, submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t); hd->ofs = ofs; hd->md = upb_fielddef_msgsubdef(f); - upb_handlers_addcleanup(h, hd, free); + upb_handlers_addcleanup(h, hd, xfree); return hd; } @@ -99,7 +99,7 @@ static const void *newoneofhandlerdata(upb_handlers *h, } else { hd->md = NULL; } - upb_handlers_addcleanup(h, hd, free); + upb_handlers_addcleanup(h, hd, xfree); return hd; } @@ -135,7 +135,7 @@ static void* appendstr_handler(void *closure, VALUE ary = (VALUE)closure; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyStringUtf8Encoding); - RepeatedField_push(ary, str); + RepeatedField_push_native(ary, &str); return (void*)str; } @@ -146,7 +146,7 @@ static void* appendbytes_handler(void *closure, VALUE ary = (VALUE)closure; VALUE str = rb_str_new2(""); rb_enc_associate(str, kRubyString8bitEncoding); - RepeatedField_push(ary, str); + RepeatedField_push_native(ary, &str); return (void*)str; } @@ -182,6 +182,23 @@ static size_t stringdata_handler(void* closure, const void* hd, return len; } +static bool stringdata_end_handler(void* closure, const void* hd) { + MessageHeader* msg = closure; + const size_t *ofs = hd; + VALUE rb_str = DEREF(msg, *ofs, VALUE); + rb_obj_freeze(rb_str); + return true; +} + +static bool appendstring_end_handler(void* closure, const void* hd) { + VALUE ary = (VALUE)closure; + int size = RepeatedField_size(ary); + VALUE* last = RepeatedField_index_native(ary, size - 1); + VALUE rb_str = *last; + rb_obj_freeze(rb_str); + return true; +} + // Appends a submessage to a repeated field (a regular Ruby array for now). static void *appendsubmsg_handler(void *closure, const void *hd) { VALUE ary = (VALUE)closure; @@ -281,7 +298,7 @@ static bool endmap_handler(void *closure, const void *hd, upb_status* s) { &frame->value_storage); Map_index_set(frame->map, key, value); - free(frame); + xfree(frame); return true; } @@ -360,6 +377,13 @@ static void *oneofbytes_handler(void *closure, return (void*)str; } +static bool oneofstring_end_handler(void* closure, const void* hd) { + MessageHeader* msg = closure; + const oneof_handlerdata_t *oneofdata = hd; + rb_obj_freeze(DEREF(msg, oneofdata->ofs, VALUE)); + return true; +} + // Handler for a submessage field in a oneof. static void *oneofsubmsg_handler(void *closure, const void *hd) { @@ -426,6 +450,7 @@ static void add_handlers_for_repeated_field(upb_handlers *h, appendbytes_handler : appendstr_handler, NULL); upb_handlers_setstring(h, f, stringdata_handler, NULL); + upb_handlers_setendstr(h, f, appendstring_end_handler, NULL); break; } case UPB_TYPE_MESSAGE: { @@ -462,6 +487,7 @@ static void add_handlers_for_singular_field(upb_handlers *h, is_bytes ? bytes_handler : str_handler, &attr); upb_handlers_setstring(h, f, stringdata_handler, &attr); + upb_handlers_setendstr(h, f, stringdata_end_handler, &attr); upb_handlerattr_uninit(&attr); break; } @@ -484,7 +510,7 @@ static void add_handlers_for_mapfield(upb_handlers* h, map_handlerdata_t* hd = new_map_handlerdata(offset, map_msgdef, desc); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlers_addcleanup(h, hd, free); + upb_handlers_addcleanup(h, hd, xfree); upb_handlerattr_sethandlerdata(&attr, hd); upb_handlers_setstartsubmsg(h, fielddef, startmapentry_handler, &attr); upb_handlerattr_uninit(&attr); @@ -499,7 +525,7 @@ static void add_handlers_for_mapentry(const upb_msgdef* msgdef, map_handlerdata_t* hd = new_map_handlerdata(0, msgdef, desc); upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlers_addcleanup(h, hd, free); + upb_handlers_addcleanup(h, hd, xfree); upb_handlerattr_sethandlerdata(&attr, hd); upb_handlers_setendmsg(h, endmap_handler, &attr); @@ -546,6 +572,7 @@ static void add_handlers_for_oneof_field(upb_handlers *h, oneofbytes_handler : oneofstr_handler, &attr); upb_handlers_setstring(h, f, stringdata_handler, NULL); + upb_handlers_setendstr(h, f, oneofstring_end_handler, &attr); break; } case UPB_TYPE_MESSAGE: { @@ -863,9 +890,13 @@ static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { assert(BUILTIN_TYPE(str) == RUBY_T_STRING); - // Ensure that the string has the correct encoding. We also check at field-set - // time, but the user may have mutated the string object since then. - native_slot_validate_string_encoding(upb_fielddef_type(f), str); + // We should be guaranteed that the string has the correct encoding because + // we ensured this at assignment time and then froze the string. + if (upb_fielddef_type(f) == UPB_TYPE_STRING) { + assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyStringUtf8Encoding); + } else { + assert(rb_enc_from_index(ENCODING_GET(value)) == kRubyString8bitEncoding); + } upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str), &subsink); diff --git a/ruby/ext/google/protobuf_c/map.c b/ruby/ext/google/protobuf_c/map.c index 92fc7286..12f1f9dd 100644 --- a/ruby/ext/google/protobuf_c/map.c +++ b/ruby/ext/google/protobuf_c/map.c @@ -63,16 +63,16 @@ // construct a key byte sequence if needed. |out_key| and |out_length| provide // the resulting key data/length. #define TABLE_KEY_BUF_LENGTH 8 // sizeof(uint64_t) -static void table_key(Map* self, VALUE key, - char* buf, - const char** out_key, - size_t* out_length) { +static VALUE table_key(Map* self, VALUE key, + char* buf, + const char** out_key, + size_t* out_length) { switch (self->key_type) { case UPB_TYPE_BYTES: case UPB_TYPE_STRING: // Strings: use string content directly. Check_Type(key, T_STRING); - native_slot_validate_string_encoding(self->key_type, key); + key = native_slot_encode_and_freeze_string(self->key_type, key); *out_key = RSTRING_PTR(key); *out_length = RSTRING_LEN(key); break; @@ -93,6 +93,8 @@ static void table_key(Map* self, VALUE key, assert(false); break; } + + return key; } static VALUE table_key_to_ruby(Map* self, const char* buf, size_t length) { @@ -357,7 +359,7 @@ VALUE Map_index(VALUE _self, VALUE key) { const char* keyval = NULL; size_t length = 0; upb_value v; - table_key(self, key, keybuf, &keyval, &length); + key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_lookup2(&self->table, keyval, length, &v)) { void* mem = value_memory(&v); @@ -383,7 +385,7 @@ VALUE Map_index_set(VALUE _self, VALUE key, VALUE value) { size_t length = 0; upb_value v; void* mem; - table_key(self, key, keybuf, &keyval, &length); + key = table_key(self, key, keybuf, &keyval, &length); mem = value_memory(&v); native_slot_set(self->value_type, self->value_type_class, mem, value); @@ -411,7 +413,7 @@ VALUE Map_has_key(VALUE _self, VALUE key) { char keybuf[TABLE_KEY_BUF_LENGTH]; const char* keyval = NULL; size_t length = 0; - table_key(self, key, keybuf, &keyval, &length); + key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_lookup2(&self->table, keyval, length, NULL)) { return Qtrue; @@ -434,7 +436,7 @@ VALUE Map_delete(VALUE _self, VALUE key) { const char* keyval = NULL; size_t length = 0; upb_value v; - table_key(self, key, keybuf, &keyval, &length); + key = table_key(self, key, keybuf, &keyval, &length); if (upb_strtable_remove2(&self->table, keyval, length, &v)) { void* mem = value_memory(&v); diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h index 2834c894..08b8d516 100644 --- a/ruby/ext/google/protobuf_c/protobuf.h +++ b/ruby/ext/google/protobuf_c/protobuf.h @@ -313,7 +313,7 @@ void native_slot_dup(upb_fieldtype_t type, void* to, void* from); void native_slot_deep_copy(upb_fieldtype_t type, void* to, void* from); bool native_slot_eq(upb_fieldtype_t type, void* mem1, void* mem2); -void native_slot_validate_string_encoding(upb_fieldtype_t type, VALUE value); +VALUE native_slot_encode_and_freeze_string(upb_fieldtype_t type, VALUE value); void native_slot_check_int_range_precision(upb_fieldtype_t type, VALUE value); extern rb_encoding* kRubyStringUtf8Encoding; @@ -366,6 +366,7 @@ RepeatedField* ruby_to_RepeatedField(VALUE value); VALUE RepeatedField_each(VALUE _self); VALUE RepeatedField_index(int argc, VALUE* argv, VALUE _self); void* RepeatedField_index_native(VALUE _self, int index); +int RepeatedField_size(VALUE _self); VALUE RepeatedField_index_set(VALUE _self, VALUE _index, VALUE val); void RepeatedField_reserve(RepeatedField* self, int new_size); VALUE RepeatedField_push(VALUE _self, VALUE val); diff --git a/ruby/ext/google/protobuf_c/repeated_field.c b/ruby/ext/google/protobuf_c/repeated_field.c index 83afbc91..47c207a5 100644 --- a/ruby/ext/google/protobuf_c/repeated_field.c +++ b/ruby/ext/google/protobuf_c/repeated_field.c @@ -244,6 +244,11 @@ void* RepeatedField_index_native(VALUE _self, int index) { return RepeatedField_memoryat(self, index, element_size); } +int RepeatedField_size(VALUE _self) { + RepeatedField* self = ruby_to_RepeatedField(_self); + return self->size; +} + /* * Private ruby method, used by RepeatedField.pop */ 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: { diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index 74a2a1db..976a3934 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -11076,8 +11076,8 @@ static bool end_stringval(upb_json_parser *p) { case UPB_TYPE_STRING: { upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); - upb_sink_endstr(&p->top->sink, sel); p->top--; + upb_sink_endstr(&p->top->sink, sel); break; } diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java index 2d4c03b5..3adaa2a8 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMap.java @@ -148,8 +148,8 @@ public class RubyMap extends RubyObject { */ @JRubyMethod(name = "[]=") public IRubyObject indexSet(ThreadContext context, IRubyObject key, IRubyObject value) { - Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass); - Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass); + key = Utils.checkType(context, keyType, key, (RubyModule) valueTypeClass); + value = Utils.checkType(context, valueType, value, (RubyModule) valueTypeClass); IRubyObject symbol; if (valueType == Descriptors.FieldDescriptor.Type.ENUM && Utils.isRubyNum(value) && diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java index 12893f73..462f8a69 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java @@ -504,7 +504,7 @@ public class RubyMessage extends RubyObject { break; case BYTES: case STRING: - Utils.validateStringEncoding(context.runtime, fieldDescriptor.getType(), value); + Utils.validateStringEncoding(context, fieldDescriptor.getType(), value); RubyString str = (RubyString) value; switch (fieldDescriptor.getType()) { case BYTES: @@ -695,7 +695,7 @@ public class RubyMessage extends RubyObject { } } if (addValue) { - Utils.checkType(context, fieldType, value, (RubyModule) typeClass); + value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); this.fields.put(fieldDescriptor, value); } else { this.fields.remove(fieldDescriptor); diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java index 946f9e74..ae2907a9 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyRepeatedField.java @@ -110,7 +110,7 @@ public class RubyRepeatedField extends RubyObject { @JRubyMethod(name = "[]=") public IRubyObject indexSet(ThreadContext context, IRubyObject index, IRubyObject value) { int arrIndex = normalizeArrayIndex(index); - Utils.checkType(context, fieldType, value, (RubyModule) typeClass); + value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); IRubyObject defaultValue = defaultValue(context); for (int i = this.storage.size(); i < arrIndex; i++) { this.storage.set(i, defaultValue); @@ -166,7 +166,7 @@ public class RubyRepeatedField extends RubyObject { public IRubyObject push(ThreadContext context, IRubyObject value) { if (!(fieldType == Descriptors.FieldDescriptor.Type.MESSAGE && value == context.runtime.getNil())) { - Utils.checkType(context, fieldType, value, (RubyModule) typeClass); + value = Utils.checkType(context, fieldType, value, (RubyModule) typeClass); } this.storage.add(value); return this.storage; diff --git a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java index 596a0979..f199feb9 100644 --- a/ruby/src/main/java/com/google/protobuf/jruby/Utils.java +++ b/ruby/src/main/java/com/google/protobuf/jruby/Utils.java @@ -64,8 +64,8 @@ public class Utils { return context.runtime.newSymbol(typeName.replace("TYPE_", "").toLowerCase()); } - public static void checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, - IRubyObject value, RubyModule typeClass) { + public static IRubyObject checkType(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, + IRubyObject value, RubyModule typeClass) { Ruby runtime = context.runtime; Object val; switch(fieldType) { @@ -106,7 +106,7 @@ public class Utils { break; case BYTES: case STRING: - validateStringEncoding(context.runtime, fieldType, value); + value = validateStringEncoding(context, fieldType, value); break; case MESSAGE: if (value.getMetaClass() != typeClass) { @@ -127,6 +127,7 @@ public class Utils { default: break; } + return value; } public static IRubyObject wrapPrimaryValue(ThreadContext context, Descriptors.FieldDescriptor.Type fieldType, Object value) { @@ -148,10 +149,16 @@ public class Utils { return runtime.newFloat((Double) value); case BOOL: return (Boolean) value ? runtime.getTrue() : runtime.getFalse(); - case BYTES: - return runtime.newString(((ByteString) value).toStringUtf8()); - case STRING: - return runtime.newString(value.toString()); + case BYTES: { + IRubyObject wrapped = runtime.newString(((ByteString) value).toStringUtf8()); + wrapped.setFrozen(true); + return wrapped; + } + case STRING: { + IRubyObject wrapped = runtime.newString(value.toString()); + wrapped.setFrozen(true); + return wrapped; + } default: return runtime.getNil(); } @@ -180,25 +187,21 @@ public class Utils { } } - public static void validateStringEncoding(Ruby runtime, Descriptors.FieldDescriptor.Type type, IRubyObject value) { + public static IRubyObject validateStringEncoding(ThreadContext context, Descriptors.FieldDescriptor.Type type, IRubyObject value) { if (!(value instanceof RubyString)) - throw runtime.newTypeError("Invalid argument for string field."); - Encoding encoding = ((RubyString) value).getEncoding(); + throw context.runtime.newTypeError("Invalid argument for string field."); switch(type) { case BYTES: - if (encoding != ASCIIEncoding.INSTANCE) - throw runtime.newTypeError("Encoding for bytes fields" + - " must be \"ASCII-8BIT\", but was " + encoding); + value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::ASCII_8BIT")); break; case STRING: - if (encoding != UTF8Encoding.INSTANCE - && encoding != USASCIIEncoding.INSTANCE) - throw runtime.newTypeError("Encoding for string fields" + - " must be \"UTF-8\" or \"ASCII\", but was " + encoding); + value = ((RubyString)value).encode(context, context.runtime.evalScriptlet("Encoding::UTF_8")); break; default: break; } + value.setFrozen(true); + return value; } public static void checkNameAvailability(ThreadContext context, String name) { diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb index fee07e33..f81e456c 100644 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -255,14 +255,17 @@ module BasicTest m = TestMessage.new # Assigning a normal (ASCII or UTF8) string to a bytes field, or - # ASCII-8BIT to a string field, raises an error. - assert_raise TypeError do - m.optional_bytes = "Test string ASCII".encode!('ASCII') - end - assert_raise TypeError do + # ASCII-8BIT to a string field will convert to the proper encoding. + m.optional_bytes = "Test string ASCII".encode!('ASCII') + assert m.optional_bytes.frozen? + assert_equal Encoding::ASCII_8BIT, m.optional_bytes.encoding + assert_equal "Test string ASCII", m.optional_bytes + + assert_raise Encoding::UndefinedConversionError do m.optional_bytes = "Test string UTF-8 \u0100".encode!('UTF-8') end - assert_raise TypeError do + + assert_raise Encoding::UndefinedConversionError do m.optional_string = ["FFFF"].pack('H*') end @@ -270,11 +273,10 @@ module BasicTest m.optional_bytes = ["FFFF"].pack('H*') m.optional_string = "\u0100" - # strings are mutable so we can do this, but serialize should catch it. + # strings are immutable so we can't do this, but serialize should catch it. m.optional_string = "asdf".encode!('UTF-8') - m.optional_string.encode!('ASCII-8BIT') - assert_raise TypeError do - data = TestMessage.encode(m) + assert_raise RuntimeError do + m.optional_string.encode!('ASCII-8BIT') end end @@ -558,7 +560,7 @@ module BasicTest assert_raise TypeError do m[1] = 1 end - assert_raise TypeError do + assert_raise Encoding::UndefinedConversionError do bytestring = ["FFFF"].pack("H*") m[bytestring] = 1 end @@ -566,9 +568,8 @@ module BasicTest m = Google::Protobuf::Map.new(:bytes, :int32) bytestring = ["FFFF"].pack("H*") m[bytestring] = 1 - assert_raise TypeError do - m["asdf"] = 1 - end + # Allowed -- we will automatically convert to ASCII-8BIT. + m["asdf"] = 1 assert_raise TypeError do m[1] = 1 end @@ -853,15 +854,22 @@ module BasicTest def test_encode_decode_helpers m = TestMessage.new(:optional_string => 'foo', :repeated_string => ['bar1', 'bar2']) + assert_equal 'foo', m.optional_string + assert_equal ['bar1', 'bar2'], m.repeated_string + json = m.to_json m2 = TestMessage.decode_json(json) - assert m2.optional_string == 'foo' - assert m2.repeated_string == ['bar1', 'bar2'] + assert_equal 'foo', m2.optional_string + assert_equal ['bar1', 'bar2'], m2.repeated_string + if RUBY_PLATFORM != "java" + assert m2.optional_string.frozen? + assert m2.repeated_string[0].frozen? + end proto = m.to_proto m2 = TestMessage.decode(proto) - assert m2.optional_string == 'foo' - assert m2.repeated_string == ['bar1', 'bar2'] + assert_equal 'foo', m2.optional_string + assert_equal ['bar1', 'bar2'], m2.repeated_string end def test_protobuf_encode_decode_helpers diff --git a/src/Makefile.am b/src/Makefile.am index 996fafa8..6e7dacfc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,8 +19,9 @@ PTHREAD_DEF = endif if GCC -# These are good warnings to turn on by default -NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wwrite-strings -Woverloaded-virtual -Wno-sign-compare +# Turn on all warnings except for sign comparison (we ignore sign comparison +# in Google so our code base have tons of such warnings). +NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) -Wall -Wno-sign-compare else NO_OPT_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) endif @@ -50,7 +51,8 @@ clean-local: rm -f *.loT CLEANFILES = $(protoc_outputs) unittest_proto_middleman \ - testzip.jar testzip.list testzip.proto testzip.zip + testzip.jar testzip.list testzip.proto testzip.zip \ + no_warning_test.cc MAINTAINERCLEANFILES = \ Makefile.in @@ -122,7 +124,6 @@ nobase_include_HEADERS = \ google/protobuf/reflection.h \ google/protobuf/reflection_ops.h \ google/protobuf/repeated_field.h \ - google/protobuf/repeated_field_reflection.h \ google/protobuf/service.h \ google/protobuf/source_context.pb.h \ google/protobuf/struct.pb.h \ @@ -680,7 +681,7 @@ COMMON_TEST_SOURCES = \ check_PROGRAMS = protoc protobuf-test protobuf-lazy-descriptor-test \ protobuf-lite-test test_plugin protobuf-lite-arena-test \ - $(GZCHECKPROGRAMS) + no-warning-test $(GZCHECKPROGRAMS) protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ ../gmock/gtest/lib/libgtest.la \ ../gmock/lib/libgmock.la \ @@ -833,6 +834,27 @@ zcgunzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la zcgunzip_SOURCES = google/protobuf/testing/zcgunzip.cc endif +# This test target is to ensure all our public header files and generated +# code is free from warnings. We have to be more pedantic about these +# files because they are compiled by users with different compiler flags. +no_warning_test.cc: + echo "// Generated from Makefile.am" > no_warning_test.cc + for FILE in $(nobase_include_HEADERS); do \ + if ! echo $${FILE} | grep "atomicops"; then \ + echo "#include <$${FILE}>" >> no_warning_test.cc; \ + fi \ + done + echo "#include <gtest/gtest.h>" >> no_warning_test.cc + echo "TEST(NoWarningTest, Empty) {}" >> no_warning_test.cc + +no_warning_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la \ + ../gmock/gtest/lib/libgtest.la \ + ../gmock/gtest/lib/libgtest_main.la +no_warning_test_CPPFLAGS = -I$(srcdir)/../gmock/gtest/include +no_warning_test_CXXFLAGS = $(PTHREAD_CFLAGS) $(PTHREAD_DEF) $(ZLIB_DEF) \ + -Wall -Werror +nodist_no_warning_test_SOURCES = no_warning_test.cc $(protoc_outputs) + TESTS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test \ google/protobuf/compiler/zip_output_unittest.sh $(GZTESTS) \ - protobuf-lite-arena-test + protobuf-lite-arena-test no-warning-test diff --git a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc index 29a8765c..a0b6d6cb 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_generator.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_generator.cc @@ -50,7 +50,12 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, OutputDirectory* output_directory, string* error) const { // ----------------------------------------------------------------- - // Parse generator options. + // Parse generator options. These options are passed to the compiler using the + // --objc_opt flag. The options are passed as a comma separated list of + // options along with their values. If the option appears multiple times, only + // the last value will be considered. + // + // e.g. protoc ... --objc_opt=expected_prefixes=file.txt,generate_for_named_framework=MyFramework Options generation_options; @@ -70,7 +75,7 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, // (i.e. - "package=prefix # comment") // // There is no validation that the prefixes are good prefixes, it is - // assume they are when you create the file. + // assumed that they are when you create the file. generation_options.expected_prefixes_path = options[i].second; } else if (options[i].first == "generate_for_named_framework") { // The name of the framework that protos are being generated for. This @@ -79,11 +84,12 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, // // NOTE: If this option is used with // named_framework_to_proto_path_mappings_path, then this is effectively - // the "default" to use for everything that wasn't mapped by the other. - generation_options.named_framework_to_proto_path_mappings_path = options[i].second; + // the "default" framework name used for everything that wasn't mapped by + // the mapping file. + generation_options.generate_for_named_framework = options[i].second; } else if (options[i].first == "named_framework_to_proto_path_mappings_path") { - // Path to find a file containing the listing of framework names and - // proto files. The generator uses this to decide if another proto file + // Path to find a file containing the list of framework names and proto + // files. The generator uses this to decide if a proto file // referenced should use a framework style import vs. a user level import // (#import <FRAMEWORK/file.pbobjc.h> vs #import "dir/file.pbobjc.h"). // @@ -97,8 +103,11 @@ bool ObjectiveCGenerator::Generate(const FileDescriptor* file, // with commas. // // There can be multiple lines listing the same frameworkName incase it - // has a lot of proto files included in it; and having multiple lines - // makes things easier to read. + // has a lot of proto files included in it; having multiple lines makes + // things easier to read. If a proto file is not configured in the + // mappings file, it will use the default framework name if one was passed + // with generate_for_named_framework, or the relative path to it's include + // path otherwise. generation_options.named_framework_to_proto_path_mappings_path = options[i].second; } else { *error = "error: Unknown generator option: " + options[i].first; diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 42bcfd94..1b9aa703 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -1250,7 +1250,7 @@ class Map { // Return whether table_[b] is a linked list that seems awfully long. // Requires table_[b] to point to a non-empty linked list. bool TableEntryIsTooLong(size_type b) { - const int kMaxLength = 8; + const size_type kMaxLength = 8; size_type count = 0; Node* node = static_cast<Node*>(table_[b]); do { diff --git a/src/google/protobuf/repeated_field_reflection.h b/src/google/protobuf/repeated_field_reflection.h deleted file mode 100644 index 512c0f1d..00000000 --- a/src/google/protobuf/repeated_field_reflection.h +++ /dev/null @@ -1,337 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This header file is protobuf internal. Users should not include this -// file directly. -#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ -#define GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ - -#include <memory> -#ifndef _SHARED_PTR_H -#include <google/protobuf/stubs/shared_ptr.h> -#endif - -#include <google/protobuf/generated_enum_reflection.h> - -namespace google { -namespace protobuf { -namespace internal { -// Interfaces used to implement reflection RepeatedFieldRef API. -// Reflection::GetRepeatedAccessor() should return a pointer to an singleton -// object that implements the below interface. -// -// This interface passes/returns values using void pointers. The actual type -// of the value depends on the field's cpp_type. Following is a mapping from -// cpp_type to the type that should be used in this interface: -// -// field->cpp_type() T Actual type of void* -// CPPTYPE_INT32 int32 int32 -// CPPTYPE_UINT32 uint32 uint32 -// CPPTYPE_INT64 int64 int64 -// CPPTYPE_UINT64 uint64 uint64 -// CPPTYPE_DOUBLE double double -// CPPTYPE_FLOAT float float -// CPPTYPE_BOOL bool bool -// CPPTYPE_ENUM generated enum type int32 -// CPPTYPE_STRING string string -// CPPTYPE_MESSAGE generated message type google::protobuf::Message -// or google::protobuf::Message -// -// Note that for enums we use int32 in the interface. -// -// You can map from T to the actual type using RefTypeTraits: -// typedef RefTypeTraits<T>::AccessorValueType ActualType; -class LIBPROTOBUF_EXPORT RepeatedFieldAccessor { - public: - // Typedefs for clarity. - typedef void Field; - typedef void Value; - typedef void Iterator; - - virtual ~RepeatedFieldAccessor(); - virtual bool IsEmpty(const Field* data) const = 0; - virtual int Size(const Field* data) const = 0; - // Depends on the underlying representation of the repeated field, this - // method can return a pointer to the underlying object if such an object - // exists, or fill the data into scratch_space and return scratch_space. - // Callers of this method must ensure scratch_space is a valid pointer - // to a mutable object of the correct type. - virtual const Value* Get( - const Field* data, int index, Value* scratch_space) const = 0; - - virtual void Clear(Field* data) const = 0; - virtual void Set(Field* data, int index, const Value* value) const = 0; - virtual void Add(Field* data, const Value* value) const = 0; - virtual void RemoveLast(Field* data) const = 0; - virtual void SwapElements(Field* data, int index1, int index2) const = 0; - virtual void Swap(Field* data, const RepeatedFieldAccessor* other_mutator, - Field* other_data) const = 0; - - // Create an iterator that points at the beginning of the repeated field. - virtual Iterator* BeginIterator(const Field* data) const = 0; - // Create an iterator that points at the end of the repeated field. - virtual Iterator* EndIterator(const Field* data) const = 0; - // Make a copy of an iterator and return the new copy. - virtual Iterator* CopyIterator(const Field* data, - const Iterator* iterator) const = 0; - // Move an iterator to point to the next element. - virtual Iterator* AdvanceIterator(const Field* data, - Iterator* iterator) const = 0; - // Compare whether two iterators point to the same element. - virtual bool EqualsIterator(const Field* data, const Iterator* a, - const Iterator* b) const = 0; - // Delete an iterator created by BeginIterator(), EndIterator() and - // CopyIterator(). - virtual void DeleteIterator(const Field* data, Iterator* iterator) const = 0; - // Like Get() but for iterators. - virtual const Value* GetIteratorValue(const Field* data, - const Iterator* iterator, - Value* scratch_space) const = 0; - - // Templated methods that make using this interface easier for non-message - // types. - template<typename T> - T Get(const Field* data, int index) const { - typedef typename RefTypeTraits<T>::AccessorValueType ActualType; - ActualType scratch_space; - return static_cast<T>( - *reinterpret_cast<const ActualType*>( - Get(data, index, static_cast<Value*>(&scratch_space)))); - } - - template<typename T, typename ValueType> - void Set(Field* data, int index, const ValueType& value) const { - typedef typename RefTypeTraits<T>::AccessorValueType ActualType; - // In this RepeatedFieldAccessor interface we pass/return data using - // raw pointers. Type of the data these raw pointers point to should - // be ActualType. Here we have a ValueType object and want a ActualType - // pointer. We can't cast a ValueType pointer to an ActualType pointer - // directly because their type might be different (for enums ValueType - // may be a generated enum type while ActualType is int32). To be safe - // we make a copy to get a temporary ActualType object and use it. - ActualType tmp = static_cast<ActualType>(value); - Set(data, index, static_cast<const Value*>(&tmp)); - } - - template<typename T, typename ValueType> - void Add(Field* data, const ValueType& value) const { - typedef typename RefTypeTraits<T>::AccessorValueType ActualType; - // In this RepeatedFieldAccessor interface we pass/return data using - // raw pointers. Type of the data these raw pointers point to should - // be ActualType. Here we have a ValueType object and want a ActualType - // pointer. We can't cast a ValueType pointer to an ActualType pointer - // directly because their type might be different (for enums ValueType - // may be a generated enum type while ActualType is int32). To be safe - // we make a copy to get a temporary ActualType object and use it. - ActualType tmp = static_cast<ActualType>(value); - Add(data, static_cast<const Value*>(&tmp)); - } -}; - -// Implement (Mutable)RepeatedFieldRef::iterator -template<typename T> -class RepeatedFieldRefIterator - : public std::iterator<std::forward_iterator_tag, T> { - typedef typename RefTypeTraits<T>::AccessorValueType AccessorValueType; - typedef typename RefTypeTraits<T>::IteratorValueType IteratorValueType; - typedef typename RefTypeTraits<T>::IteratorPointerType IteratorPointerType; - - public: - // Constructor for non-message fields. - RepeatedFieldRefIterator(const void* data, - const RepeatedFieldAccessor* accessor, - bool begin) - : data_(data), accessor_(accessor), - iterator_(begin ? accessor->BeginIterator(data) : - accessor->EndIterator(data)), - scratch_space_(new AccessorValueType) { - } - // Constructor for message fields. - RepeatedFieldRefIterator(const void* data, - const RepeatedFieldAccessor* accessor, - bool begin, - AccessorValueType* scratch_space) - : data_(data), accessor_(accessor), - iterator_(begin ? accessor->BeginIterator(data) : - accessor->EndIterator(data)), - scratch_space_(scratch_space) { - } - ~RepeatedFieldRefIterator() { - accessor_->DeleteIterator(data_, iterator_); - } - RepeatedFieldRefIterator operator++(int) { - RepeatedFieldRefIterator tmp(*this); - iterator_ = accessor_->AdvanceIterator(data_, iterator_); - return tmp; - } - RepeatedFieldRefIterator& operator++() { - iterator_ = accessor_->AdvanceIterator(data_, iterator_); - return *this; - } - IteratorValueType operator*() const { - return static_cast<IteratorValueType>( - *static_cast<const AccessorValueType*>( - accessor_->GetIteratorValue( - data_, iterator_, scratch_space_.get()))); - } - IteratorPointerType operator->() const { - return static_cast<IteratorPointerType>( - accessor_->GetIteratorValue( - data_, iterator_, scratch_space_.get())); - } - bool operator!=(const RepeatedFieldRefIterator& other) const { - assert(data_ == other.data_); - assert(accessor_ == other.accessor_); - return !accessor_->EqualsIterator(data_, iterator_, other.iterator_); - } - bool operator==(const RepeatedFieldRefIterator& other) const { - return !this->operator!=(other); - } - - RepeatedFieldRefIterator(const RepeatedFieldRefIterator& other) - : data_(other.data_), accessor_(other.accessor_), - iterator_(accessor_->CopyIterator(data_, other.iterator_)) { - } - RepeatedFieldRefIterator& operator=(const RepeatedFieldRefIterator& other) { - if (this != &other) { - accessor_->DeleteIterator(data_, iterator_); - data_ = other.data_; - accessor_ = other.accessor_; - iterator_ = accessor_->CopyIterator(data_, other.iterator_); - } - return *this; - } - - protected: - const void* data_; - const RepeatedFieldAccessor* accessor_; - void* iterator_; - google::protobuf::scoped_ptr<AccessorValueType> scratch_space_; -}; - -// TypeTraits that maps the type parameter T of RepeatedFieldRef or -// MutableRepeatedFieldRef to corresponding iterator type, -// RepeatedFieldAccessor type, etc. -template<typename T> -struct PrimitiveTraits { - static const bool is_primitive = false; -}; -#define DEFINE_PRIMITIVE(TYPE, type) \ - template<> struct PrimitiveTraits<type> { \ - static const bool is_primitive = true; \ - static const FieldDescriptor::CppType cpp_type = \ - FieldDescriptor::CPPTYPE_ ## TYPE; \ - }; -DEFINE_PRIMITIVE(INT32, int32) -DEFINE_PRIMITIVE(UINT32, uint32) -DEFINE_PRIMITIVE(INT64, int64) -DEFINE_PRIMITIVE(UINT64, uint64) -DEFINE_PRIMITIVE(FLOAT, float) -DEFINE_PRIMITIVE(DOUBLE, double) -DEFINE_PRIMITIVE(BOOL, bool) -#undef DEFINE_PRIMITIVE - -template<typename T> -struct RefTypeTraits< - T, typename internal::enable_if<PrimitiveTraits<T>::is_primitive>::type> { - typedef RepeatedFieldRefIterator<T> iterator; - typedef RepeatedFieldAccessor AccessorType; - typedef T AccessorValueType; - typedef T IteratorValueType; - typedef T* IteratorPointerType; - static const FieldDescriptor::CppType cpp_type = - PrimitiveTraits<T>::cpp_type; - static const Descriptor* GetMessageFieldDescriptor() { - return NULL; - } -}; - -template<typename T> -struct RefTypeTraits< - T, typename internal::enable_if<is_proto_enum<T>::value>::type> { - typedef RepeatedFieldRefIterator<T> iterator; - typedef RepeatedFieldAccessor AccessorType; - // We use int32 for repeated enums in RepeatedFieldAccessor. - typedef int32 AccessorValueType; - typedef T IteratorValueType; - typedef int32* IteratorPointerType; - static const FieldDescriptor::CppType cpp_type = - FieldDescriptor::CPPTYPE_ENUM; - static const Descriptor* GetMessageFieldDescriptor() { - return NULL; - } -}; - -template<typename T> -struct RefTypeTraits< - T, typename internal::enable_if<internal::is_same<string, T>::value>::type> { - typedef RepeatedFieldRefIterator<T> iterator; - typedef RepeatedFieldAccessor AccessorType; - typedef string AccessorValueType; - typedef string IteratorValueType; - typedef string* IteratorPointerType; - static const FieldDescriptor::CppType cpp_type = - FieldDescriptor::CPPTYPE_STRING; - static const Descriptor* GetMessageFieldDescriptor() { - return NULL; - } -}; - -template<typename T> -struct MessageDescriptorGetter { - static const Descriptor* get() { - return T::default_instance().GetDescriptor(); - } -}; -template<> -struct MessageDescriptorGetter<Message> { - static const Descriptor* get() { - return NULL; - } -}; - -template<typename T> -struct RefTypeTraits< - T, typename internal::enable_if<internal::is_base_of<Message, T>::value>::type> { - typedef RepeatedFieldRefIterator<T> iterator; - typedef RepeatedFieldAccessor AccessorType; - typedef Message AccessorValueType; - typedef const T& IteratorValueType; - typedef const T* IteratorPointerType; - static const FieldDescriptor::CppType cpp_type = - FieldDescriptor::CPPTYPE_MESSAGE; - static const Descriptor* GetMessageFieldDescriptor() { - return MessageDescriptorGetter<T>::get(); - } -}; -} // namespace internal -} // namespace protobuf -} // namespace google -#endif // GOOGLE_PROTOBUF_REPEATED_FIELD_REFLECTION_H__ diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index ebd858ff..93d7c824 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -346,9 +346,9 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive( io::CodedInputStream* input, RepeatedField<CType>* values) { int length; if (!input->ReadVarintSizeAsInt(&length)) return false; - const uint32 old_entries = values->size(); - const uint32 new_entries = length / sizeof(CType); - const uint32 new_bytes = new_entries * sizeof(CType); + const int old_entries = values->size(); + const int new_entries = length / sizeof(CType); + const int new_bytes = new_entries * sizeof(CType); if (new_bytes != length) return false; // We would *like* to pre-allocate the buffer to write into (for // speed), but *must* avoid performing a very large allocation due @@ -382,7 +382,7 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive( #else values->Reserve(old_entries + new_entries); CType value; - for (uint32 i = 0; i < new_entries; ++i) { + for (int i = 0; i < new_entries; ++i) { if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false; values->AddAlreadyReserved(value); } @@ -392,7 +392,7 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive( // safely allocate. We read as much as we can into *values // without pre-allocating "length" bytes. CType value; - for (uint32 i = 0; i < new_entries; ++i) { + for (int i = 0; i < new_entries; ++i) { if (!ReadPrimitive<CType, DeclaredType>(input, &value)) return false; values->Add(value); } |