google-protobuf 3.15.0.rc.2 → 3.15.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of google-protobuf might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b2f79dec339070aae3653aad69f267295dadc4a4b22c06d2d6f043768ddd079
4
- data.tar.gz: 2b85d0d37e6062fed98e7b4bb1518ce785b1e698207f2d5b8cd12f6ca6d8f114
3
+ metadata.gz: 46c2622ad6f76f6c6d68c895a9a3fd8fd4c017040ffd2692b7af45c3550537b1
4
+ data.tar.gz: a58556ee162ecbefaf6752b3ae2e2c8b237d771239cafdb6964770219ee85023
5
5
  SHA512:
6
- metadata.gz: 9ee412b5657b03a460ea6864de46fc620a273124e59d91b0ee888fa0b9465f93c58672af6c03d60e9965bfb894a6c596f44b8683660bb7be1d28839821988e93
7
- data.tar.gz: 114ed541c956a3bde8ed36995f96c13e5ab9951697c3559b8a39d94203edb35e674014a494d6594447b3b3a268a1afabd71889052e99c07463c98e3ae00e9ee4
6
+ metadata.gz: 94cd6e0e0d2f179254448862f3987a54d184b3e0f2f73ea81738cb9498cc4a36c01bdf5bb8d5e454f1dfe4d6f313a9df2df544b72c45518673145b1d1461486c
7
+ data.tar.gz: 9e147c6e490a000b9a247e6911c52d5f55f824cbf4dfd1e57489139c97e25d4a829a17de3c7e8f71f3a953890784d76822dea6d9977a74363c2536f012d71d92
@@ -295,7 +295,7 @@ static VALUE DescriptorPool_alloc(VALUE klass) {
295
295
 
296
296
  self->def_to_descriptor = rb_hash_new();
297
297
  self->symtab = upb_symtab_new();
298
- ObjectCache_Add(self->symtab, ret, _upb_symtab_arena(self->symtab));
298
+ ObjectCache_Add(self->symtab, ret);
299
299
 
300
300
  return ret;
301
301
  }
@@ -960,16 +960,14 @@ static VALUE FieldDescriptor_subtype(VALUE _self) {
960
960
  static VALUE FieldDescriptor_get(VALUE _self, VALUE msg_rb) {
961
961
  FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
962
962
  const upb_msgdef *m;
963
- const upb_msgdef *msg = Message_Get(msg_rb, &m);
964
- VALUE arena = Message_GetArena(msg_rb);
965
- upb_msgval msgval;
963
+
964
+ Message_Get(msg_rb, &m);
966
965
 
967
966
  if (m != upb_fielddef_containingtype(self->fielddef)) {
968
967
  rb_raise(cTypeError, "get method called on wrong message type");
969
968
  }
970
969
 
971
- msgval = upb_msg_get(msg, self->fielddef);
972
- return Convert_UpbToRuby(msgval, TypeInfo_get(self->fielddef), arena);
970
+ return Message_getfield(msg_rb, self->fielddef);
973
971
  }
974
972
 
975
973
  /*
@@ -93,7 +93,7 @@ VALUE Map_GetRubyWrapper(upb_map* map, upb_fieldtype_t key_type,
93
93
  if (val == Qnil) {
94
94
  val = Map_alloc(cMap);
95
95
  Map* self;
96
- ObjectCache_Add(map, val, Arena_get(arena));
96
+ ObjectCache_Add(map, val);
97
97
  TypedData_Get_Struct(val, Map, &Map_type, self);
98
98
  self->map = map;
99
99
  self->arena = arena;
@@ -318,7 +318,7 @@ static VALUE Map_init(int argc, VALUE* argv, VALUE _self) {
318
318
 
319
319
  self->map = upb_map_new(Arena_get(self->arena), self->key_type,
320
320
  self->value_type_info.type);
321
- ObjectCache_Add(self->map, _self, Arena_get(self->arena));
321
+ ObjectCache_Add(self->map, _self);
322
322
 
323
323
  if (init_arg != Qnil) {
324
324
  Map_merge_into_self(_self, init_arg);
@@ -590,9 +590,10 @@ VALUE Map_eq(VALUE _self, VALUE _other) {
590
590
  */
591
591
  static VALUE Map_freeze(VALUE _self) {
592
592
  Map* self = ruby_to_Map(_self);
593
-
594
- ObjectCache_Pin(self->map, _self, Arena_get(self->arena));
595
- RB_OBJ_FREEZE(_self);
593
+ if (!RB_OBJ_FROZEN(_self)) {
594
+ Arena_Pin(self->arena, _self);
595
+ RB_OBJ_FREEZE(_self);
596
+ }
596
597
  return _self;
597
598
  }
598
599
 
@@ -105,7 +105,7 @@ void Message_InitPtr(VALUE self_, upb_msg *msg, VALUE arena) {
105
105
  Message* self = ruby_to_Message(self_);
106
106
  self->msg = msg;
107
107
  self->arena = arena;
108
- ObjectCache_Add(msg, self_, Arena_get(arena));
108
+ ObjectCache_Add(msg, self_);
109
109
  }
110
110
 
111
111
  VALUE Message_GetArena(VALUE msg_rb) {
@@ -292,6 +292,35 @@ static void Message_setfield(upb_msg* msg, const upb_fielddef* f, VALUE val,
292
292
  upb_msg_set(msg, f, msgval, arena);
293
293
  }
294
294
 
295
+ VALUE Message_getfield(VALUE _self, const upb_fielddef* f) {
296
+ Message* self = ruby_to_Message(_self);
297
+ // This is a special-case: upb_msg_mutable() for map & array are logically
298
+ // const (they will not change what is serialized) but physically
299
+ // non-const, as they do allocate a repeated field or map. The logical
300
+ // constness means it's ok to do even if the message is frozen.
301
+ upb_msg *msg = (upb_msg*)self->msg;
302
+ upb_arena *arena = Arena_get(self->arena);
303
+ if (upb_fielddef_ismap(f)) {
304
+ upb_map *map = upb_msg_mutable(msg, f, arena).map;
305
+ const upb_fielddef *key_f = map_field_key(f);
306
+ const upb_fielddef *val_f = map_field_value(f);
307
+ upb_fieldtype_t key_type = upb_fielddef_type(key_f);
308
+ TypeInfo value_type_info = TypeInfo_get(val_f);
309
+ return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
310
+ } else if (upb_fielddef_isseq(f)) {
311
+ upb_array *arr = upb_msg_mutable(msg, f, arena).array;
312
+ return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
313
+ } else if (upb_fielddef_issubmsg(f)) {
314
+ if (!upb_msg_has(self->msg, f)) return Qnil;
315
+ upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
316
+ const upb_msgdef *m = upb_fielddef_msgsubdef(f);
317
+ return Message_GetRubyWrapper(submsg, m, self->arena);
318
+ } else {
319
+ upb_msgval msgval = upb_msg_get(self->msg, f);
320
+ return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
321
+ }
322
+ }
323
+
295
324
  static VALUE Message_field_accessor(VALUE _self, const upb_fielddef* f,
296
325
  int accessor_type, int argc, VALUE* argv) {
297
326
  upb_arena *arena = Arena_get(Message_GetArena(_self));
@@ -350,36 +379,11 @@ static VALUE Message_field_accessor(VALUE _self, const upb_fielddef* f,
350
379
  return INT2NUM(msgval.int32_val);
351
380
  }
352
381
  }
353
- case METHOD_GETTER: {
354
- Message* self = ruby_to_Message(_self);
355
- // This is a special-case: upb_msg_mutable() for map & array are logically
356
- // const (they will not change what is serialized) but physically
357
- // non-const, as they do allocate a repeated field or map. The logical
358
- // constness means it's ok to do even if the message is frozen.
359
- upb_msg *msg = (upb_msg*)self->msg;
360
- if (upb_fielddef_ismap(f)) {
361
- upb_map *map = upb_msg_mutable(msg, f, arena).map;
362
- const upb_fielddef *key_f = map_field_key(f);
363
- const upb_fielddef *val_f = map_field_value(f);
364
- upb_fieldtype_t key_type = upb_fielddef_type(key_f);
365
- TypeInfo value_type_info = TypeInfo_get(val_f);
366
- return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
367
- } else if (upb_fielddef_isseq(f)) {
368
- upb_array *arr = upb_msg_mutable(msg, f, arena).array;
369
- return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
370
- } else if (upb_fielddef_issubmsg(f)) {
371
- if (!upb_msg_has(self->msg, f)) return Qnil;
372
- upb_msg *submsg = upb_msg_mutable(msg, f, arena).msg;
373
- const upb_msgdef *m = upb_fielddef_msgsubdef(f);
374
- return Message_GetRubyWrapper(submsg, m, self->arena);
375
- } else {
376
- upb_msgval msgval = upb_msg_get(self->msg, f);
377
- return Convert_UpbToRuby(msgval, TypeInfo_get(f), self->arena);
378
- }
382
+ case METHOD_GETTER:
383
+ return Message_getfield(_self, f);
379
384
  default:
380
385
  rb_raise(rb_eRuntimeError, "Internal error, no such accessor: %d",
381
386
  accessor_type);
382
- }
383
387
  }
384
388
  }
385
389
 
@@ -851,8 +855,10 @@ static VALUE Message_to_h(VALUE _self) {
851
855
  */
852
856
  static VALUE Message_freeze(VALUE _self) {
853
857
  Message* self = ruby_to_Message(_self);
854
- ObjectCache_Pin(self->msg, _self, Arena_get(self->arena));
855
- RB_OBJ_FREEZE(_self);
858
+ if (!RB_OBJ_FROZEN(_self)) {
859
+ Arena_Pin(self->arena, _self);
860
+ RB_OBJ_FREEZE(_self);
861
+ }
856
862
  return _self;
857
863
  }
858
864
 
@@ -866,7 +872,6 @@ static VALUE Message_freeze(VALUE _self) {
866
872
  static VALUE Message_index(VALUE _self, VALUE field_name) {
867
873
  Message* self = ruby_to_Message(_self);
868
874
  const upb_fielddef* field;
869
- upb_msgval val;
870
875
 
871
876
  Check_Type(field_name, T_STRING);
872
877
  field = upb_msgdef_ntofz(self->msgdef, RSTRING_PTR(field_name));
@@ -875,8 +880,7 @@ static VALUE Message_index(VALUE _self, VALUE field_name) {
875
880
  return Qnil;
876
881
  }
877
882
 
878
- val = upb_msg_get(self->msg, field);
879
- return Convert_UpbToRuby(val, TypeInfo_get(field), self->arena);
883
+ return Message_getfield(_self, field);
880
884
  }
881
885
 
882
886
  /*
@@ -1246,7 +1250,9 @@ upb_msg* Message_deep_copy(const upb_msg* msg, const upb_msgdef* m,
1246
1250
 
1247
1251
  const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
1248
1252
  const char* name, upb_arena* arena) {
1249
- if (value == Qnil) return NULL;
1253
+ if (value == Qnil) {
1254
+ rb_raise(cTypeError, "nil message not allowed here.");
1255
+ }
1250
1256
 
1251
1257
  VALUE klass = CLASS_OF(value);
1252
1258
  VALUE desc_rb = rb_ivar_get(klass, descriptor_instancevar_interned);
@@ -1285,7 +1291,7 @@ const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
1285
1291
  if (!rb_obj_is_kind_of(value, rb_cNumeric)) goto badtype;
1286
1292
 
1287
1293
  sec.int64_val = NUM2LL(value);
1288
- nsec.int32_val = (NUM2DBL(value) - NUM2LL(value)) * 1000000000;
1294
+ nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
1289
1295
  upb_msg_set(msg, sec_f, sec, arena);
1290
1296
  upb_msg_set(msg, nsec_f, nsec, arena);
1291
1297
  return msg;
@@ -63,6 +63,9 @@ const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
63
63
  // object will reference |arena| and ensure that it outlives this object.
64
64
  VALUE Message_GetRubyWrapper(upb_msg* msg, const upb_msgdef* m, VALUE arena);
65
65
 
66
+ // Gets the given field from this message.
67
+ VALUE Message_getfield(VALUE _self, const upb_fielddef* f);
68
+
66
69
  // Implements #inspect for this message, printing the text to |b|.
67
70
  void Message_PrintMessage(StringBuilder* b, const upb_msg* msg,
68
71
  const upb_msgdef* m);
@@ -167,30 +167,55 @@ void StringBuilder_PrintMsgval(StringBuilder* b, upb_msgval val,
167
167
  // Arena
168
168
  // -----------------------------------------------------------------------------
169
169
 
170
- void Arena_free(void* data) { upb_arena_free(data); }
170
+ typedef struct {
171
+ upb_arena *arena;
172
+ VALUE pinned_objs;
173
+ } Arena;
174
+
175
+ static void Arena_mark(void *data) {
176
+ Arena *arena = data;
177
+ rb_gc_mark(arena->pinned_objs);
178
+ }
179
+
180
+ static void Arena_free(void *data) {
181
+ Arena *arena = data;
182
+ upb_arena_free(arena->arena);
183
+ }
171
184
 
172
185
  static VALUE cArena;
173
186
 
174
187
  const rb_data_type_t Arena_type = {
175
188
  "Google::Protobuf::Internal::Arena",
176
- { NULL, Arena_free, NULL },
189
+ { Arena_mark, Arena_free, NULL },
190
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
177
191
  };
178
192
 
179
193
  static VALUE Arena_alloc(VALUE klass) {
180
- upb_arena *arena = upb_arena_new();
194
+ Arena *arena = ALLOC(Arena);
195
+ arena->arena = upb_arena_new();
196
+ arena->pinned_objs = Qnil;
181
197
  return TypedData_Wrap_Struct(klass, &Arena_type, arena);
182
198
  }
183
199
 
184
200
  upb_arena *Arena_get(VALUE _arena) {
185
- upb_arena *arena;
186
- TypedData_Get_Struct(_arena, upb_arena, &Arena_type, arena);
187
- return arena;
201
+ Arena *arena;
202
+ TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
203
+ return arena->arena;
188
204
  }
189
205
 
190
206
  VALUE Arena_new() {
191
207
  return Arena_alloc(cArena);
192
208
  }
193
209
 
210
+ void Arena_Pin(VALUE _arena, VALUE obj) {
211
+ Arena *arena;
212
+ TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
213
+ if (arena->pinned_objs == Qnil) {
214
+ arena->pinned_objs = rb_ary_new();
215
+ }
216
+ rb_ary_push(arena->pinned_objs, obj);
217
+ }
218
+
194
219
  void Arena_register(VALUE module) {
195
220
  VALUE internal = rb_define_module_under(module, "Internal");
196
221
  VALUE klass = rb_define_class_under(internal, "Arena", rb_cObject);
@@ -209,122 +234,79 @@ void Arena_register(VALUE module) {
209
234
  // different wrapper objects for the same C object, which saves memory and
210
235
  // preserves object identity.
211
236
  //
212
- // We use Hash and/or WeakMap for the cache. WeakMap is faster overall
213
- // (probably due to removal being integrated with GC) but doesn't work for Ruby
214
- // <2.7 (see note below). We need Hash for Ruby <2.7 and for cases where we
215
- // need to GC-root the object (notably when the object has been frozen).
237
+ // We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
238
+ // to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
239
+ // keys.
216
240
 
217
241
  #if RUBY_API_VERSION_CODE >= 20700
218
- #define USE_WEAK_MAP 1
242
+ #define USE_SECONDARY_MAP 0
219
243
  #else
220
- #define USE_WEAK_MAP 0
244
+ #define USE_SECONDARY_MAP 1
221
245
  #endif
222
246
 
223
- static VALUE ObjectCache_GetKey(const void* key) {
224
- char buf[sizeof(key)];
225
- memcpy(&buf, &key, sizeof(key));
226
- intptr_t key_int = (intptr_t)key;
227
- PBRUBY_ASSERT((key_int & 3) == 0);
228
- return LL2NUM(key_int >> 2);
229
- }
247
+ #if USE_SECONDARY_MAP
230
248
 
231
- // Strong object cache, uses regular Hash and GC-roots objects.
232
- // - For Ruby <2.7, used for all objects.
233
- // - For Ruby >=2.7, used only for frozen objects, so we preserve the "frozen"
234
- // bit (since this information is not preserved at the upb level).
249
+ // Maps Numeric -> Object. The object is then used as a key into the WeakMap.
250
+ // This is needed for Ruby <2.7 where a number cannot be a key to WeakMap.
251
+ // The object is used only for its identity; it does not contain any data.
252
+ VALUE secondary_map = Qnil;
235
253
 
236
- VALUE strong_obj_cache = Qnil;
237
-
238
- static void StrongObjectCache_Init() {
239
- rb_gc_register_address(&strong_obj_cache);
240
- strong_obj_cache = rb_hash_new();
254
+ static void SecondaryMap_Init() {
255
+ rb_gc_register_address(&secondary_map);
256
+ secondary_map = rb_hash_new();
241
257
  }
242
258
 
243
- static void StrongObjectCache_Remove(void* key) {
244
- VALUE key_rb = ObjectCache_GetKey(key);
245
- PBRUBY_ASSERT(rb_hash_lookup(strong_obj_cache, key_rb) != Qnil);
246
- rb_hash_delete(strong_obj_cache, key_rb);
259
+ static VALUE SecondaryMap_Get(VALUE key) {
260
+ VALUE ret = rb_hash_lookup(secondary_map, key);
261
+ if (ret == Qnil) {
262
+ ret = rb_eval_string("Object.new");
263
+ rb_hash_aset(secondary_map, key, ret);
264
+ }
265
+ return ret;
247
266
  }
248
267
 
249
- static VALUE StrongObjectCache_Get(const void* key) {
250
- VALUE key_rb = ObjectCache_GetKey(key);
251
- return rb_hash_lookup(strong_obj_cache, key_rb);
252
- }
268
+ #endif
253
269
 
254
- static void StrongObjectCache_Add(const void* key, VALUE val,
255
- upb_arena* arena) {
256
- PBRUBY_ASSERT(StrongObjectCache_Get(key) == Qnil);
257
- VALUE key_rb = ObjectCache_GetKey(key);
258
- rb_hash_aset(strong_obj_cache, key_rb, val);
259
- upb_arena_addcleanup(arena, (void*)key, StrongObjectCache_Remove);
270
+ static VALUE ObjectCache_GetKey(const void* key) {
271
+ char buf[sizeof(key)];
272
+ memcpy(&buf, &key, sizeof(key));
273
+ intptr_t key_int = (intptr_t)key;
274
+ PBRUBY_ASSERT((key_int & 3) == 0);
275
+ VALUE ret = LL2NUM(key_int >> 2);
276
+ #if USE_SECONDARY_MAP
277
+ ret = SecondaryMap_Get(ret);
278
+ #endif
279
+ return ret;
260
280
  }
261
281
 
262
- // Weak object cache. This speeds up the test suite significantly, so we
263
- // presume it speeds up real code also. However we can only use it in Ruby
264
- // >=2.7 due to:
265
- // https://bugs.ruby-lang.org/issues/16035
266
-
267
- #if USE_WEAK_MAP
282
+ // Public ObjectCache API.
268
283
 
269
284
  VALUE weak_obj_cache = Qnil;
285
+ ID item_get;
286
+ ID item_set;
270
287
 
271
- static void WeakObjectCache_Init() {
288
+ static void ObjectCache_Init() {
272
289
  rb_gc_register_address(&weak_obj_cache);
273
290
  VALUE klass = rb_eval_string("ObjectSpace::WeakMap");
274
291
  weak_obj_cache = rb_class_new_instance(0, NULL, klass);
275
- }
276
-
277
- static VALUE WeakObjectCache_Get(const void* key) {
278
- VALUE key_rb = ObjectCache_GetKey(key);
279
- VALUE ret = rb_funcall(weak_obj_cache, rb_intern("[]"), 1, key_rb);
280
- return ret;
281
- }
282
-
283
- static void WeakObjectCache_Add(const void* key, VALUE val) {
284
- PBRUBY_ASSERT(WeakObjectCache_Get(key) == Qnil);
285
- VALUE key_rb = ObjectCache_GetKey(key);
286
- rb_funcall(weak_obj_cache, rb_intern("[]="), 2, key_rb, val);
287
- PBRUBY_ASSERT(WeakObjectCache_Get(key) == val);
288
- }
289
-
290
- #endif
291
-
292
- // Public ObjectCache API.
293
-
294
- static void ObjectCache_Init() {
295
- StrongObjectCache_Init();
296
- #if USE_WEAK_MAP
297
- WeakObjectCache_Init();
292
+ item_get = rb_intern("[]");
293
+ item_set = rb_intern("[]=");
294
+ #if USE_SECONDARY_MAP
295
+ SecondaryMap_Init();
298
296
  #endif
299
297
  }
300
298
 
301
- void ObjectCache_Add(const void* key, VALUE val, upb_arena *arena) {
302
- #if USE_WEAK_MAP
303
- (void)arena;
304
- WeakObjectCache_Add(key, val);
305
- #else
306
- StrongObjectCache_Add(key, val, arena);
307
- #endif
299
+ void ObjectCache_Add(const void* key, VALUE val) {
300
+ PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
301
+ VALUE key_rb = ObjectCache_GetKey(key);
302
+ rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
303
+ PBRUBY_ASSERT(ObjectCache_Get(key) == val);
308
304
  }
309
305
 
310
306
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
311
307
  VALUE ObjectCache_Get(const void* key) {
312
- #if USE_WEAK_MAP
313
- return WeakObjectCache_Get(key);
314
- #else
315
- return StrongObjectCache_Get(key);
316
- #endif
317
- }
318
-
319
- void ObjectCache_Pin(const void* key, VALUE val, upb_arena *arena) {
320
- #if USE_WEAK_MAP
321
- PBRUBY_ASSERT(WeakObjectCache_Get(key) == val);
322
- // This will GC-root the object, but we'll still use the weak map for
323
- // actual lookup.
324
- StrongObjectCache_Add(key, val, arena);
325
- #else
326
- // Value is already pinned, nothing to do.
327
- #endif
308
+ VALUE key_rb = ObjectCache_GetKey(key);
309
+ return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
328
310
  }
329
311
 
330
312
  /*
@@ -55,6 +55,13 @@ const upb_fielddef* map_field_value(const upb_fielddef* field);
55
55
  VALUE Arena_new();
56
56
  upb_arena *Arena_get(VALUE arena);
57
57
 
58
+ // Pins this Ruby object to the lifetime of this arena, so that as long as the
59
+ // arena is alive this object will not be collected.
60
+ //
61
+ // We use this to guarantee that the "frozen" bit on the object will be
62
+ // remembered, even if the user drops their reference to this precise object.
63
+ void Arena_Pin(VALUE arena, VALUE obj);
64
+
58
65
  // -----------------------------------------------------------------------------
59
66
  // ObjectCache
60
67
  // -----------------------------------------------------------------------------
@@ -68,19 +75,11 @@ upb_arena *Arena_get(VALUE arena);
68
75
  // Adds an entry to the cache. The "arena" parameter must give the arena that
69
76
  // "key" was allocated from. In Ruby <2.7.0, it will be used to remove the key
70
77
  // from the cache when the arena is destroyed.
71
- void ObjectCache_Add(const void* key, VALUE val, upb_arena *arena);
78
+ void ObjectCache_Add(const void* key, VALUE val);
72
79
 
73
80
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
74
81
  VALUE ObjectCache_Get(const void* key);
75
82
 
76
- // Pins the previously added object so it is GC-rooted. This turns the
77
- // reference to "val" from weak to strong. We use this to guarantee that the
78
- // "frozen" bit on the object will be remembered, even if the user drops their
79
- // reference to this precise object.
80
- //
81
- // The "arena" parameter must give the arena that "key" was allocated from.
82
- void ObjectCache_Pin(const void* key, VALUE val, upb_arena *arena);
83
-
84
83
  // -----------------------------------------------------------------------------
85
84
  // StringBuilder, for inspect
86
85
  // -----------------------------------------------------------------------------
@@ -88,7 +88,7 @@ VALUE RepeatedField_GetRubyWrapper(upb_array* array, TypeInfo type_info,
88
88
  if (val == Qnil) {
89
89
  val = RepeatedField_alloc(cRepeatedField);
90
90
  RepeatedField* self;
91
- ObjectCache_Add(array, val, Arena_get(arena));
91
+ ObjectCache_Add(array, val);
92
92
  TypedData_Get_Struct(val, RepeatedField, &RepeatedField_type, self);
93
93
  self->array = array;
94
94
  self->arena = arena;
@@ -500,9 +500,10 @@ VALUE RepeatedField_eq(VALUE _self, VALUE _other) {
500
500
  */
501
501
  static VALUE RepeatedField_freeze(VALUE _self) {
502
502
  RepeatedField* self = ruby_to_RepeatedField(_self);
503
-
504
- ObjectCache_Pin(self->array, _self, Arena_get(self->arena));
505
- RB_OBJ_FREEZE(_self);
503
+ if (!RB_OBJ_FROZEN(_self)) {
504
+ Arena_Pin(self->arena, _self);
505
+ RB_OBJ_FREEZE(_self);
506
+ }
506
507
  return _self;
507
508
  }
508
509
 
@@ -610,7 +611,7 @@ VALUE RepeatedField_init(int argc, VALUE* argv, VALUE _self) {
610
611
 
611
612
  self->type_info = TypeInfo_FromClass(argc, argv, 0, &self->type_class, &ary);
612
613
  self->array = upb_array_new(arena, self->type_info.type);
613
- ObjectCache_Add(self->array, _self, arena);
614
+ ObjectCache_Add(self->array, _self);
614
615
 
615
616
  if (ary != Qnil) {
616
617
  if (!RB_TYPE_P(ary, T_ARRAY)) {
data/tests/basic.rb CHANGED
@@ -31,6 +31,38 @@ module BasicTest
31
31
  end
32
32
  include CommonTests
33
33
 
34
+ def test_issue_8311_crash
35
+ Google::Protobuf::DescriptorPool.generated_pool.build do
36
+ add_file("inner.proto", :syntax => :proto3) do
37
+ add_message "Inner" do
38
+ # Removing either of these fixes the segfault.
39
+ optional :foo, :string, 1
40
+ optional :bar, :string, 2
41
+ end
42
+ end
43
+ end
44
+
45
+ Google::Protobuf::DescriptorPool.generated_pool.build do
46
+ add_file("outer.proto", :syntax => :proto3) do
47
+ add_message "Outer" do
48
+ repeated :inners, :message, 1, "Inner"
49
+ end
50
+ end
51
+ end
52
+
53
+ outer = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("Outer").msgclass
54
+
55
+ outer.new(
56
+ inners: []
57
+ )['inners'].to_s
58
+
59
+ assert_raise Google::Protobuf::TypeError do
60
+ outer.new(
61
+ inners: [nil]
62
+ ).to_s
63
+ end
64
+ end
65
+
34
66
  def test_has_field
35
67
  m = TestSingularFields.new
36
68
  assert !m.has_singular_msg?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: google-protobuf
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.15.0.rc.2
4
+ version: 3.15.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Protobuf Authors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-17 00:00:00.000000000 Z
11
+ date: 2021-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler-dock
@@ -123,7 +123,7 @@ homepage: https://developers.google.com/protocol-buffers
123
123
  licenses:
124
124
  - BSD-3-Clause
125
125
  metadata:
126
- source_code_uri: https://github.com/protocolbuffers/protobuf/tree/v3.15.0-rc2/ruby
126
+ source_code_uri: https://github.com/protocolbuffers/protobuf/tree/v3.15.4/ruby
127
127
  post_install_message:
128
128
  rdoc_options: []
129
129
  require_paths:
@@ -135,11 +135,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
135
  version: '2.3'
136
136
  required_rubygems_version: !ruby/object:Gem::Requirement
137
137
  requirements:
138
- - - ">"
138
+ - - ">="
139
139
  - !ruby/object:Gem::Version
140
- version: 1.3.1
140
+ version: '0'
141
141
  requirements: []
142
- rubygems_version: 3.2.11
142
+ rubygems_version: 3.2.13
143
143
  signing_key:
144
144
  specification_version: 4
145
145
  summary: Protocol Buffers