google-protobuf 3.15.6 → 3.17.3

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: e6f2d2b024b64eb8c142ff7eaea74a58431a8a12f936ab7152ab5c8721efd121
4
- data.tar.gz: 4ed37ac80d30d80f12a18d1b9608b4793d1d25304937b80fdb031cae748a8da2
3
+ metadata.gz: b1ded185284a923b15342a8f5600e74debdd40f99faf40c35c1b8675636406ff
4
+ data.tar.gz: '018d94176b65ef8ddcb7b27b785dfaac029ada709e999e58bcc194bff018f984'
5
5
  SHA512:
6
- metadata.gz: a42d5b9110675cb943a6add8acb5981d81ebbed4827adea17d7d5a819b42dd3e1ae9d0a5cf26288ab4f90f6a6ca28d3325ac431043e50510703aa5fafbef9cac
7
- data.tar.gz: 1774c58e9133f64859d84745a39b099b43a0006b331b1926cab3e42ccc8e352c03e1dce990d050253f9c537fb07ed230af10c85558379c68864320a016e1a0e3
6
+ metadata.gz: f0c47bf01f20c9327b089e60d2bb36d1eee98483eb862e7434b9409a5b18dc24ab38808660b997fbbb66ed21fa012417aaeb1164019ea715c7547d5928ca1d37
7
+ data.tar.gz: 01e37346bed78463df8a19d1b60315494065094b13aa4f76bbffb872be51f163297542d8a6db2a8d7902c2987312e06f23d3b55e2ed6833f988733c90f11e97c
@@ -868,6 +868,20 @@ static VALUE FieldDescriptor_default(VALUE _self) {
868
868
  return Convert_UpbToRuby(default_val, TypeInfo_get(self->fielddef), Qnil);
869
869
  }
870
870
 
871
+
872
+ /*
873
+ * call-seq:
874
+ * FieldDescriptor.json_name => json_name
875
+ *
876
+ * Returns this field's json_name, as a Ruby string, or nil if not yet set.
877
+ */
878
+ static VALUE FieldDescriptor_json_name(VALUE _self) {
879
+ FieldDescriptor* self = ruby_to_FieldDescriptor(_self);
880
+ const upb_fielddef *f = self->fielddef;
881
+ const char *json_name = upb_fielddef_jsonname(f);
882
+ return rb_str_new2(json_name);
883
+ }
884
+
871
885
  /*
872
886
  * call-seq:
873
887
  * FieldDescriptor.label => label
@@ -1043,6 +1057,7 @@ static void FieldDescriptor_register(VALUE module) {
1043
1057
  rb_define_method(klass, "name", FieldDescriptor_name, 0);
1044
1058
  rb_define_method(klass, "type", FieldDescriptor__type, 0);
1045
1059
  rb_define_method(klass, "default", FieldDescriptor_default, 0);
1060
+ rb_define_method(klass, "json_name", FieldDescriptor_json_name, 0);
1046
1061
  rb_define_method(klass, "label", FieldDescriptor_label, 0);
1047
1062
  rb_define_method(klass, "number", FieldDescriptor_number, 0);
1048
1063
  rb_define_method(klass, "submsg_name", FieldDescriptor_submsg_name, 0);
@@ -1750,6 +1765,16 @@ static void msgdef_add_field(VALUE msgbuilder_rb, upb_label_t label, VALUE name,
1750
1765
  field_proto,
1751
1766
  FileBuilderContext_strdup(self->file_builder, default_value));
1752
1767
  }
1768
+
1769
+ if (rb_funcall(options, rb_intern("key?"), 1,
1770
+ ID2SYM(rb_intern("json_name"))) == Qtrue) {
1771
+ VALUE json_name =
1772
+ rb_hash_lookup(options, ID2SYM(rb_intern("json_name")));
1773
+
1774
+ google_protobuf_FieldDescriptorProto_set_json_name(
1775
+ field_proto,
1776
+ FileBuilderContext_strdup(self->file_builder, json_name));
1777
+ }
1753
1778
  }
1754
1779
 
1755
1780
  if (oneof_index >= 0) {
@@ -1899,18 +1924,20 @@ static VALUE MessageBuilderContext_required(int argc, VALUE* argv,
1899
1924
  */
1900
1925
  static VALUE MessageBuilderContext_repeated(int argc, VALUE* argv,
1901
1926
  VALUE _self) {
1902
- VALUE name, type, number, type_class;
1927
+ VALUE name, type, number;
1928
+ VALUE type_class, options = Qnil;
1903
1929
 
1904
- if (argc < 3) {
1905
- rb_raise(rb_eArgError, "Expected at least 3 arguments.");
1930
+ rb_scan_args(argc, argv, "32", &name, &type, &number, &type_class, &options);
1931
+
1932
+ // Allow passing (name, type, number, options) or
1933
+ // (name, type, number, type_class, options)
1934
+ if (argc == 4 && RB_TYPE_P(type_class, T_HASH)) {
1935
+ options = type_class;
1936
+ type_class = Qnil;
1906
1937
  }
1907
- name = argv[0];
1908
- type = argv[1];
1909
- number = argv[2];
1910
- type_class = (argc > 3) ? argv[3] : Qnil;
1911
1938
 
1912
1939
  msgdef_add_field(_self, UPB_LABEL_REPEATED, name, type, number, type_class,
1913
- Qnil, -1, false);
1940
+ options, -1, false);
1914
1941
 
1915
1942
  return Qnil;
1916
1943
  }
@@ -17,4 +17,5 @@ end
17
17
  $objs = ["protobuf.o", "convert.o", "defs.o", "message.o",
18
18
  "repeated_field.o", "map.o", "ruby-upb.o", "wrap_memcpy.o"]
19
19
 
20
+ find_header('third_party/wyhash/wyhash.h', '../../../..')
20
21
  create_makefile("google/protobuf_c")
@@ -167,7 +167,8 @@ VALUE Map_deep_copy(VALUE obj) {
167
167
  new_arena_rb);
168
168
  }
169
169
 
170
- const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef *field) {
170
+ const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef* field,
171
+ upb_arena* arena) {
171
172
  const upb_fielddef* key_field = map_field_key(field);
172
173
  const upb_fielddef* value_field = map_field_value(field);
173
174
  TypeInfo value_type_info = TypeInfo_get(value_field);
@@ -189,6 +190,7 @@ const upb_map* Map_GetUpbMap(VALUE val, const upb_fielddef *field) {
189
190
  rb_raise(cTypeError, "Map value type has wrong message/enum class");
190
191
  }
191
192
 
193
+ Arena_fuse(self->arena, arena);
192
194
  return self->map;
193
195
  }
194
196
 
@@ -236,7 +238,7 @@ static VALUE Map_merge_into_self(VALUE _self, VALUE hashmap) {
236
238
  upb_msg *self_msg = Map_GetMutable(_self);
237
239
  size_t iter = UPB_MAP_BEGIN;
238
240
 
239
- upb_arena_fuse(arena, Arena_get(other->arena));
241
+ Arena_fuse(other->arena, arena);
240
242
 
241
243
  if (self->key_type != other->key_type ||
242
244
  self->value_type_info.type != other->value_type_info.type ||
@@ -511,7 +513,7 @@ static VALUE Map_dup(VALUE _self) {
511
513
  upb_arena *arena = Arena_get(new_self->arena);
512
514
  upb_map *new_map = Map_GetMutable(new_map_rb);
513
515
 
514
- upb_arena_fuse(arena, Arena_get(self->arena));
516
+ Arena_fuse(self->arena, arena);
515
517
 
516
518
  while (upb_mapiter_next(self->map, &iter)) {
517
519
  upb_msgval key = upb_mapiter_key(self->map, iter);
@@ -44,7 +44,8 @@ VALUE Map_GetRubyWrapper(upb_map *map, upb_fieldtype_t key_type,
44
44
  // Gets the underlying upb_map for this Ruby map object, which must have
45
45
  // key/value type that match |field|. If this is not a map or the type doesn't
46
46
  // match, raises an exception.
47
- const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field);
47
+ const upb_map *Map_GetUpbMap(VALUE val, const upb_fielddef *field,
48
+ upb_arena *arena);
48
49
 
49
50
  // Implements #inspect for this map by appending its contents to |b|.
50
51
  void Map_Inspect(StringBuilder *b, const upb_map *map, upb_fieldtype_t key_type,
@@ -277,9 +277,9 @@ static void Message_setfield(upb_msg* msg, const upb_fielddef* f, VALUE val,
277
277
  upb_arena* arena) {
278
278
  upb_msgval msgval;
279
279
  if (upb_fielddef_ismap(f)) {
280
- msgval.map_val = Map_GetUpbMap(val, f);
280
+ msgval.map_val = Map_GetUpbMap(val, f, arena);
281
281
  } else if (upb_fielddef_isseq(f)) {
282
- msgval.array_val = RepeatedField_GetUpbArray(val, f);
282
+ msgval.array_val = RepeatedField_GetUpbArray(val, f, arena);
283
283
  } else {
284
284
  if (val == Qnil &&
285
285
  (upb_fielddef_issubmsg(f) || upb_fielddef_realcontainingoneof(f))) {
@@ -660,7 +660,7 @@ static VALUE Message_dup(VALUE _self) {
660
660
  // TODO(copy unknown fields?)
661
661
  // TODO(use official upb msg copy function)
662
662
  memcpy((upb_msg*)new_msg_self->msg, self->msg, size);
663
- upb_arena_fuse(Arena_get(new_msg_self->arena), Arena_get(self->arena));
663
+ Arena_fuse(self->arena, Arena_get(new_msg_self->arena));
664
664
  return new_msg;
665
665
  }
666
666
 
@@ -697,16 +697,13 @@ bool Message_Equal(const upb_msg *m1, const upb_msg *m2, const upb_msgdef *m) {
697
697
  * field is of a primitive type).
698
698
  */
699
699
  static VALUE Message_eq(VALUE _self, VALUE _other) {
700
- if (TYPE(_self) != TYPE(_other)) {
701
- return Qfalse;
702
- }
700
+ if (CLASS_OF(_self) != CLASS_OF(_other)) return Qfalse;
703
701
 
704
702
  Message* self = ruby_to_Message(_self);
705
703
  Message* other = ruby_to_Message(_other);
704
+ assert(self->msgdef == other->msgdef);
706
705
 
707
- return Message_Equal(self->msg, other->msg, self->msgdef)
708
- ? Qtrue
709
- : Qfalse;
706
+ return Message_Equal(self->msg, other->msg, self->msgdef) ? Qtrue : Qfalse;
710
707
  }
711
708
 
712
709
  uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
@@ -737,7 +734,10 @@ uint64_t Message_Hash(const upb_msg* msg, const upb_msgdef* m, uint64_t seed) {
737
734
  */
738
735
  static VALUE Message_hash(VALUE _self) {
739
736
  Message* self = ruby_to_Message(_self);
740
- return INT2FIX(Message_Hash(self->msg, self->msgdef, 0));
737
+ uint64_t hash_value = Message_Hash(self->msg, self->msgdef, 0);
738
+ // RUBY_FIXNUM_MAX should be one less than a power of 2.
739
+ assert((RUBY_FIXNUM_MAX & (RUBY_FIXNUM_MAX + 1)) == 0);
740
+ return INT2FIX(hash_value & RUBY_FIXNUM_MAX);
741
741
  }
742
742
 
743
743
  /*
@@ -794,6 +794,14 @@ static VALUE Message_CreateHash(const upb_msg *msg, const upb_msgdef *m) {
794
794
  VALUE msg_value;
795
795
  VALUE msg_key;
796
796
 
797
+ if (!is_proto2 && upb_fielddef_issubmsg(field) &&
798
+ !upb_fielddef_isseq(field) && !upb_msg_has(msg, field)) {
799
+ // TODO: Legacy behavior, remove when we fix the is_proto2 differences.
800
+ msg_key = ID2SYM(rb_intern(upb_fielddef_name(field)));
801
+ rb_hash_aset(hash, msg_key, Qnil);
802
+ continue;
803
+ }
804
+
797
805
  // Do not include fields that are not present (oneof or optional fields).
798
806
  if (is_proto2 && upb_fielddef_haspresence(field) &&
799
807
  !upb_msg_has(msg, field)) {
@@ -1306,7 +1314,7 @@ const upb_msg* Message_GetUpbMessage(VALUE value, const upb_msgdef* m,
1306
1314
  }
1307
1315
 
1308
1316
  Message* self = ruby_to_Message(value);
1309
- upb_arena_fuse(arena, Arena_get(self->arena));
1317
+ Arena_fuse(self->arena, arena);
1310
1318
 
1311
1319
  return self->msg;
1312
1320
  }
@@ -37,7 +37,7 @@
37
37
  #include "message.h"
38
38
  #include "repeated_field.h"
39
39
 
40
- VALUE cError;
40
+ VALUE cParseError;
41
41
  VALUE cTypeError;
42
42
 
43
43
  const upb_fielddef* map_field_key(const upb_fielddef* field) {
@@ -180,6 +180,7 @@ static void Arena_mark(void *data) {
180
180
  static void Arena_free(void *data) {
181
181
  Arena *arena = data;
182
182
  upb_arena_free(arena->arena);
183
+ xfree(arena);
183
184
  }
184
185
 
185
186
  static VALUE cArena;
@@ -203,6 +204,16 @@ upb_arena *Arena_get(VALUE _arena) {
203
204
  return arena->arena;
204
205
  }
205
206
 
207
+ void Arena_fuse(VALUE _arena, upb_arena *other) {
208
+ Arena *arena;
209
+ TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
210
+ if (!upb_arena_fuse(arena->arena, other)) {
211
+ rb_raise(rb_eRuntimeError,
212
+ "Unable to fuse arenas. This should never happen since Ruby does "
213
+ "not use initial blocks");
214
+ }
215
+ }
216
+
206
217
  VALUE Arena_new() {
207
218
  return Arena_alloc(cArena);
208
219
  }
@@ -237,8 +248,16 @@ void Arena_register(VALUE module) {
237
248
  // We use WeakMap for the cache. For Ruby <2.7 we also need a secondary Hash
238
249
  // to store WeakMap keys because Ruby <2.7 WeakMap doesn't allow non-finalizable
239
250
  // keys.
240
-
241
- #if RUBY_API_VERSION_CODE >= 20700
251
+ //
252
+ // We also need the secondary Hash if sizeof(long) < sizeof(VALUE), because this
253
+ // means it may not be possible to fit a pointer into a Fixnum. Keys are
254
+ // pointers, and if they fit into a Fixnum, Ruby doesn't collect them, but if
255
+ // they overflow and require allocating a Bignum, they could get collected
256
+ // prematurely, thus removing the cache entry. This happens on 64-bit Windows,
257
+ // on which pointers are 64 bits but longs are 32 bits. In this case, we enable
258
+ // the secondary Hash to hold the keys and prevent them from being collected.
259
+
260
+ #if RUBY_API_VERSION_CODE >= 20700 && SIZEOF_LONG >= SIZEOF_VALUE
242
261
  #define USE_SECONDARY_MAP 0
243
262
  #else
244
263
  #define USE_SECONDARY_MAP 1
@@ -251,15 +270,81 @@ void Arena_register(VALUE module) {
251
270
  // The object is used only for its identity; it does not contain any data.
252
271
  VALUE secondary_map = Qnil;
253
272
 
273
+ // Mutations to the map are under a mutex, because SeconaryMap_MaybeGC()
274
+ // iterates over the map which cannot happen in parallel with insertions, or
275
+ // Ruby will throw:
276
+ // can't add a new key into hash during iteration (RuntimeError)
277
+ VALUE secondary_map_mutex = Qnil;
278
+
279
+ // Lambda that will GC entries from the secondary map that are no longer present
280
+ // in the primary map.
281
+ VALUE gc_secondary_map_lambda = Qnil;
282
+ ID length;
283
+
284
+ extern VALUE weak_obj_cache;
285
+
254
286
  static void SecondaryMap_Init() {
255
287
  rb_gc_register_address(&secondary_map);
288
+ rb_gc_register_address(&gc_secondary_map_lambda);
289
+ rb_gc_register_address(&secondary_map_mutex);
256
290
  secondary_map = rb_hash_new();
291
+ gc_secondary_map_lambda = rb_eval_string(
292
+ "->(secondary, weak) {\n"
293
+ " secondary.delete_if { |k, v| !weak.key?(v) }\n"
294
+ "}\n");
295
+ secondary_map_mutex = rb_mutex_new();
296
+ length = rb_intern("length");
257
297
  }
258
298
 
259
- static VALUE SecondaryMap_Get(VALUE key) {
299
+ // The secondary map is a regular Hash, and will never shrink on its own.
300
+ // The main object cache is a WeakMap that will automatically remove entries
301
+ // when the target object is no longer reachable, but unless we manually
302
+ // remove the corresponding entries from the secondary map, it will grow
303
+ // without bound.
304
+ //
305
+ // To avoid this unbounded growth we periodically remove entries from the
306
+ // secondary map that are no longer present in the WeakMap. The logic of
307
+ // how often to perform this GC is an artbirary tuning parameter that
308
+ // represents a straightforward CPU/memory tradeoff.
309
+ //
310
+ // Requires: secondary_map_mutex is held.
311
+ static void SecondaryMap_MaybeGC() {
312
+ PBRUBY_ASSERT(rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
313
+ size_t weak_len = NUM2ULL(rb_funcall(weak_obj_cache, length, 0));
314
+ size_t secondary_len = RHASH_SIZE(secondary_map);
315
+ if (secondary_len < weak_len) {
316
+ // Logically this case should not be possible: a valid entry cannot exist in
317
+ // the weak table unless there is a corresponding entry in the secondary
318
+ // table. It should *always* be the case that secondary_len >= weak_len.
319
+ //
320
+ // However ObjectSpace::WeakMap#length (and therefore weak_len) is
321
+ // unreliable: it overreports its true length by including non-live objects.
322
+ // However these non-live objects are not yielded in iteration, so we may
323
+ // have previously deleted them from the secondary map in a previous
324
+ // invocation of SecondaryMap_MaybeGC().
325
+ //
326
+ // In this case, we can't measure any waste, so we just return.
327
+ return;
328
+ }
329
+ size_t waste = secondary_len - weak_len;
330
+ // GC if we could remove at least 2000 entries or 20% of the table size
331
+ // (whichever is greater). Since the cost of the GC pass is O(N), we
332
+ // want to make sure that we condition this on overall table size, to
333
+ // avoid O(N^2) CPU costs.
334
+ size_t threshold = PBRUBY_MAX(secondary_len * 0.2, 2000);
335
+ if (waste > threshold) {
336
+ rb_funcall(gc_secondary_map_lambda, rb_intern("call"), 2,
337
+ secondary_map, weak_obj_cache);
338
+ }
339
+ }
340
+
341
+ // Requires: secondary_map_mutex is held by this thread iff create == true.
342
+ static VALUE SecondaryMap_Get(VALUE key, bool create) {
343
+ PBRUBY_ASSERT(!create || rb_mutex_locked_p(secondary_map_mutex) == Qtrue);
260
344
  VALUE ret = rb_hash_lookup(secondary_map, key);
261
- if (ret == Qnil) {
262
- ret = rb_eval_string("Object.new");
345
+ if (ret == Qnil && create) {
346
+ SecondaryMap_MaybeGC();
347
+ ret = rb_class_new_instance(0, NULL, rb_cObject);
263
348
  rb_hash_aset(secondary_map, key, ret);
264
349
  }
265
350
  return ret;
@@ -267,14 +352,13 @@ static VALUE SecondaryMap_Get(VALUE key) {
267
352
 
268
353
  #endif
269
354
 
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);
355
+ // Requires: secondary_map_mutex is held by this thread iff create == true.
356
+ static VALUE ObjectCache_GetKey(const void* key, bool create) {
357
+ VALUE key_val = (VALUE)key;
358
+ PBRUBY_ASSERT((key_val & 3) == 0);
359
+ VALUE ret = LL2NUM(key_val >> 2);
276
360
  #if USE_SECONDARY_MAP
277
- ret = SecondaryMap_Get(ret);
361
+ ret = SecondaryMap_Get(ret, create);
278
362
  #endif
279
363
  return ret;
280
364
  }
@@ -298,14 +382,20 @@ static void ObjectCache_Init() {
298
382
 
299
383
  void ObjectCache_Add(const void* key, VALUE val) {
300
384
  PBRUBY_ASSERT(ObjectCache_Get(key) == Qnil);
301
- VALUE key_rb = ObjectCache_GetKey(key);
385
+ #if USE_SECONDARY_MAP
386
+ rb_mutex_lock(secondary_map_mutex);
387
+ #endif
388
+ VALUE key_rb = ObjectCache_GetKey(key, true);
302
389
  rb_funcall(weak_obj_cache, item_set, 2, key_rb, val);
390
+ #if USE_SECONDARY_MAP
391
+ rb_mutex_unlock(secondary_map_mutex);
392
+ #endif
303
393
  PBRUBY_ASSERT(ObjectCache_Get(key) == val);
304
394
  }
305
395
 
306
396
  // Returns the cached object for this key, if any. Otherwise returns Qnil.
307
397
  VALUE ObjectCache_Get(const void* key) {
308
- VALUE key_rb = ObjectCache_GetKey(key);
398
+ VALUE key_rb = ObjectCache_GetKey(key, false);
309
399
  return rb_funcall(weak_obj_cache, item_get, 1, key_rb);
310
400
  }
311
401
 
@@ -368,8 +458,10 @@ void Init_protobuf_c() {
368
458
  Map_register(protobuf);
369
459
  Message_register(protobuf);
370
460
 
371
- cError = rb_const_get(protobuf, rb_intern("Error"));
461
+ cParseError = rb_const_get(protobuf, rb_intern("ParseError"));
462
+ rb_gc_register_mark_object(cParseError);
372
463
  cTypeError = rb_const_get(protobuf, rb_intern("TypeError"));
464
+ rb_gc_register_mark_object(cTypeError);
373
465
 
374
466
  rb_define_singleton_method(protobuf, "discard_unknown",
375
467
  Google_Protobuf_discard_unknown, 1);
@@ -55,6 +55,10 @@ 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
+ // Fuses this arena to another, throwing a Ruby exception if this is not
59
+ // possible.
60
+ void Arena_fuse(VALUE arena, upb_arena *other);
61
+
58
62
  // Pins this Ruby object to the lifetime of this arena, so that as long as the
59
63
  // arena is alive this object will not be collected.
60
64
  //
@@ -106,6 +110,8 @@ extern VALUE cTypeError;
106
110
  #define PBRUBY_ASSERT(expr) assert(expr)
107
111
  #endif
108
112
 
113
+ #define PBRUBY_MAX(x, y) (((x) > (y)) ? (x) : (y))
114
+
109
115
  #define UPB_UNUSED(var) (void)var
110
116
 
111
117
  #endif // __GOOGLE_PROTOBUF_RUBY_PROTOBUF_H__
@@ -149,7 +149,8 @@ VALUE RepeatedField_deep_copy(VALUE _self) {
149
149
  return new_rptfield;
150
150
  }
151
151
 
152
- const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef *field) {
152
+ const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef* field,
153
+ upb_arena* arena) {
153
154
  RepeatedField* self;
154
155
  TypeInfo type_info = TypeInfo_get(field);
155
156
 
@@ -167,6 +168,7 @@ const upb_array* RepeatedField_GetUpbArray(VALUE val, const upb_fielddef *field)
167
168
  rb_raise(cTypeError, "Repeated field array has wrong message/enum class");
168
169
  }
169
170
 
171
+ Arena_fuse(self->arena, arena);
170
172
  return self->array;
171
173
  }
172
174
 
@@ -412,7 +414,7 @@ static VALUE RepeatedField_dup(VALUE _self) {
412
414
  int size = upb_array_size(self->array);
413
415
  int i;
414
416
 
415
- upb_arena_fuse(arena, Arena_get(self->arena));
417
+ Arena_fuse(self->arena, arena);
416
418
 
417
419
  for (i = 0; i < size; i++) {
418
420
  upb_msgval msgval = upb_array_get(self->array, i);
@@ -44,7 +44,8 @@ VALUE RepeatedField_GetRubyWrapper(upb_array* msg, TypeInfo type_info,
44
44
  // Gets the underlying upb_array for this Ruby RepeatedField object, which must
45
45
  // have a type that matches |f|. If this is not a repeated field or the type
46
46
  // doesn't match, raises an exception.
47
- const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f);
47
+ const upb_array* RepeatedField_GetUpbArray(VALUE value, const upb_fielddef* f,
48
+ upb_arena* arena);
48
49
 
49
50
  // Implements #inspect for this repeated field by appending its contents to |b|.
50
51
  void RepeatedField_Inspect(StringBuilder* b, const upb_array* array,