google-protobuf 4.36.2-java → 4.37.0.rc.1-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45ff720d519c7b536a3fa27f6a141cff023010b405e5ab2cfd9c2a510562e500
4
- data.tar.gz: 856019695a1ab061f54ed34c0c801ad15592e477204dfb3ed7505ad81e9273e1
3
+ metadata.gz: 2cff40a754cba2763c4bdd5bac2ea7ed53266991c7ba26d985d79f34b2d99e3d
4
+ data.tar.gz: 0cd3f1806abab5b5a62390493debb96d66bbd05c6e0521dc379c516cb0466a9e
5
5
  SHA512:
6
- metadata.gz: 74acc1f8c637b6c6506901492820cbae8388e23a1619b12d2bd3d06bd84e73b6979902e297f1b478c0f8fbf8bdf13576efbf8e3463a065b7076bfe93391541e1
7
- data.tar.gz: 2c1b18cf842df0592fdcf7be6b109c54716efbf4f500e779c44b261e50e837839892564f04333efe214c9ec484c60a7b70b78d4039b7be8c5c027c896f8e8a14
6
+ metadata.gz: 973a8163db63fa331207141ef170cba75abab4d1ed4d558c64d95929994e5561fe3acab7a712a0de036a64f8c834a37801a3194a6128503dd4ea459eecefd546
7
+ data.tar.gz: 54067bee74a01cbe063ac6c534d4b2c9c2ff4bdf45cc74bc8be47310f5847f19cb36931455680e424165763524c1ad8ef4acc003775183bb88749372818af859
@@ -286,7 +286,9 @@ static void Message_setfield(upb_Message* msg, const upb_FieldDef* f, VALUE val,
286
286
  msgval =
287
287
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
288
288
  }
289
- upb_Message_SetFieldByDef(msg, f, msgval, arena);
289
+ if (!upb_Message_SetFieldByDef(msg, f, msgval, arena)) {
290
+ Arena_raise_oom();
291
+ }
290
292
  }
291
293
 
292
294
  VALUE Message_getfield_frozen(const upb_Message* msg, const upb_FieldDef* f,
@@ -328,6 +330,7 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
328
330
  upb_Arena* arena = Arena_get(self->arena);
329
331
  if (upb_FieldDef_IsMap(f)) {
330
332
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
333
+ if (!map) Arena_raise_oom();
331
334
  const upb_FieldDef* key_f = map_field_key(f);
332
335
  const upb_FieldDef* val_f = map_field_value(f);
333
336
  upb_CType key_type = upb_FieldDef_CType(key_f);
@@ -335,10 +338,12 @@ VALUE Message_getfield(VALUE _self, const upb_FieldDef* f) {
335
338
  return Map_GetRubyWrapper(map, key_type, value_type_info, self->arena);
336
339
  } else if (upb_FieldDef_IsRepeated(f)) {
337
340
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
341
+ if (!arr) Arena_raise_oom();
338
342
  return RepeatedField_GetRubyWrapper(arr, TypeInfo_get(f), self->arena);
339
343
  } else if (upb_FieldDef_IsSubMessage(f)) {
340
344
  if (!upb_Message_HasFieldByDef(msg, f)) return Qnil;
341
345
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
346
+ if (!submsg) Arena_raise_oom();
342
347
  const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f);
343
348
  return Message_GetRubyWrapper(submsg, m, self->arena);
344
349
  } else {
@@ -390,7 +395,10 @@ static VALUE Message_field_accessor(VALUE _self, const upb_FieldDef* f,
390
395
  upb_MessageValue msgval = Convert_RubyToUpb(
391
396
  argv[1], upb_FieldDef_Name(f), TypeInfo_get(val_f), arena);
392
397
  upb_Message* wrapper = upb_Message_Mutable(msg, f, arena).msg;
393
- upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena);
398
+ if (!wrapper) Arena_raise_oom();
399
+ if (!upb_Message_SetFieldByDef(wrapper, val_f, msgval, arena)) {
400
+ Arena_raise_oom();
401
+ }
394
402
  }
395
403
  return Qnil;
396
404
  }
@@ -519,19 +527,25 @@ typedef struct {
519
527
  static int Map_initialize_kwarg(VALUE key, VALUE val, VALUE _self) {
520
528
  MapInit* map_init = (MapInit*)_self;
521
529
  upb_MessageValue k, v;
522
- k = Convert_RubyToUpb(key, "", map_init->key_type, NULL);
530
+ // Copy the key into the arena rather than aliasing it: building the value
531
+ // below allocates, which can trigger GC and free or move the String the key
532
+ // would otherwise point into.
533
+ k = Convert_RubyToUpb(key, "", map_init->key_type, map_init->arena);
523
534
 
524
535
  if (map_init->val_type.type == kUpb_CType_Message && TYPE(val) == T_HASH) {
525
536
  const upb_MiniTable* t =
526
537
  upb_MessageDef_MiniTable(map_init->val_type.def.msgdef);
527
538
  upb_Message* msg = upb_Message_New(t, map_init->arena);
539
+ if (!msg) Arena_raise_oom();
528
540
  Message_InitFromValue(msg, map_init->val_type.def.msgdef, val,
529
541
  map_init->arena);
530
542
  v.msg_val = msg;
531
543
  } else {
532
544
  v = Convert_RubyToUpb(val, "", map_init->val_type, map_init->arena);
533
545
  }
534
- upb_Map_Set(map_init->map, k, v, map_init->arena);
546
+ if (!upb_Map_Set(map_init->map, k, v, map_init->arena)) {
547
+ Arena_raise_oom();
548
+ }
535
549
  return ST_CONTINUE;
536
550
  }
537
551
 
@@ -556,6 +570,7 @@ static upb_MessageValue MessageValue_FromValue(VALUE val, TypeInfo info,
556
570
  upb_MessageValue msgval;
557
571
  const upb_MiniTable* t = upb_MessageDef_MiniTable(info.def.msgdef);
558
572
  upb_Message* msg = upb_Message_New(t, arena);
573
+ if (!msg) Arena_raise_oom();
559
574
  Message_InitFromValue(msg, info.def.msgdef, val, arena);
560
575
  msgval.msg_val = msg;
561
576
  return msgval;
@@ -583,7 +598,9 @@ static void RepeatedField_InitFromValue(upb_Array* arr, const upb_FieldDef* f,
583
598
  } else {
584
599
  msgval = Convert_RubyToUpb(entry, upb_FieldDef_Name(f), type_info, arena);
585
600
  }
586
- upb_Array_Append(arr, msgval, arena);
601
+ if (!upb_Array_Append(arr, msgval, arena)) {
602
+ Arena_raise_oom();
603
+ }
587
604
  }
588
605
  }
589
606
 
@@ -593,13 +610,16 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
593
610
 
594
611
  if (upb_FieldDef_IsMap(f)) {
595
612
  upb_Map* map = upb_Message_Mutable(msg, f, arena).map;
613
+ if (!map) Arena_raise_oom();
596
614
  Map_InitFromValue(map, f, val, arena);
597
615
  } else if (upb_FieldDef_IsRepeated(f)) {
598
616
  upb_Array* arr = upb_Message_Mutable(msg, f, arena).array;
617
+ if (!arr) Arena_raise_oom();
599
618
  RepeatedField_InitFromValue(arr, f, val, arena);
600
619
  } else if (upb_FieldDef_IsSubMessage(f)) {
601
620
  if (TYPE(val) == T_HASH) {
602
621
  upb_Message* submsg = upb_Message_Mutable(msg, f, arena).msg;
622
+ if (!submsg) Arena_raise_oom();
603
623
  Message_InitFromValue(submsg, upb_FieldDef_MessageSubDef(f), val, arena);
604
624
  } else {
605
625
  Message_setfield(msg, f, val, arena);
@@ -607,7 +627,9 @@ static void Message_InitFieldFromValue(upb_Message* msg, const upb_FieldDef* f,
607
627
  } else {
608
628
  upb_MessageValue msgval =
609
629
  Convert_RubyToUpb(val, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
610
- upb_Message_SetFieldByDef(msg, f, msgval, arena);
630
+ if (!upb_Message_SetFieldByDef(msg, f, msgval, arena)) {
631
+ Arena_raise_oom();
632
+ }
611
633
  }
612
634
  }
613
635
 
@@ -668,6 +690,7 @@ static VALUE Message_initialize(int argc, VALUE* argv, VALUE _self) {
668
690
  upb_Arena* arena = Arena_get(arena_rb);
669
691
  const upb_MiniTable* t = upb_MessageDef_MiniTable(self->msgdef);
670
692
  upb_Message* msg = upb_Message_New(t, arena);
693
+ if (!msg) Arena_raise_oom();
671
694
 
672
695
  Message_InitPtr(_self, msg, arena_rb);
673
696
 
@@ -733,6 +756,9 @@ uint64_t Message_Hash(const upb_Message* msg, const upb_MessageDef* m,
733
756
  if (upb_Status_IsOk(&status)) {
734
757
  return return_value;
735
758
  } else {
759
+ if (strcmp(upb_Status_ErrorMessage(&status), "Out of memory") == 0) {
760
+ Arena_raise_oom();
761
+ }
736
762
  rb_raise(cParseError, "Message_Hash(): %s",
737
763
  upb_Status_ErrorMessage(&status));
738
764
  }
@@ -774,25 +800,64 @@ static VALUE Message_inspect(VALUE _self) {
774
800
 
775
801
  // Support functions for Message_to_h //////////////////////////////////////////
776
802
 
777
- static VALUE RepeatedField_CreateArray(const upb_Array* arr,
778
- TypeInfo type_info) {
803
+ static VALUE RepeatedField_CreateArray(const upb_Array* arr, TypeInfo type_info,
804
+ bool emit_defaults) {
779
805
  int size = arr ? upb_Array_Size(arr) : 0;
780
806
  VALUE ary = rb_ary_new2(size);
781
807
 
782
808
  for (int i = 0; i < size; i++) {
783
809
  upb_MessageValue msgval = upb_Array_Get(arr, i);
784
- VALUE val = Scalar_CreateHash(msgval, type_info);
810
+ VALUE val = Scalar_CreateHash(msgval, type_info, emit_defaults);
785
811
  rb_ary_push(ary, val);
786
812
  }
787
813
 
788
814
  return ary;
789
815
  }
790
816
 
791
- static VALUE Message_CreateHash(const upb_Message* msg,
792
- const upb_MessageDef* m) {
817
+ static VALUE Message_CreateHash(const upb_Message* msg, const upb_MessageDef* m,
818
+ bool emit_defaults) {
793
819
  if (!msg) return Qnil;
794
820
 
795
821
  VALUE hash = rb_hash_new();
822
+
823
+ if (emit_defaults) {
824
+ int n = upb_MessageDef_FieldCount(m);
825
+
826
+ for (int i = 0; i < n; i++) {
827
+ const upb_FieldDef* field = upb_MessageDef_Field(m, i);
828
+
829
+ if (upb_FieldDef_HasPresence(field) &&
830
+ !upb_Message_HasFieldByDef(msg, field)) {
831
+ continue;
832
+ }
833
+
834
+ TypeInfo type_info = TypeInfo_get(field);
835
+ upb_MessageValue val = upb_Message_GetFieldByDef(msg, field);
836
+ VALUE msg_value;
837
+
838
+ if (upb_FieldDef_IsMap(field)) {
839
+ const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(field);
840
+ const upb_FieldDef* key_f =
841
+ upb_MessageDef_FindFieldByNumber(entry_m, 1);
842
+ const upb_FieldDef* val_f =
843
+ upb_MessageDef_FindFieldByNumber(entry_m, 2);
844
+ upb_CType key_type = upb_FieldDef_CType(key_f);
845
+ msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f),
846
+ emit_defaults);
847
+ } else if (upb_FieldDef_IsRepeated(field)) {
848
+ msg_value =
849
+ RepeatedField_CreateArray(val.array_val, type_info, emit_defaults);
850
+ } else {
851
+ msg_value = Scalar_CreateHash(val, type_info, emit_defaults);
852
+ }
853
+
854
+ VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
855
+ rb_hash_aset(hash, msg_key, msg_value);
856
+ }
857
+
858
+ return hash;
859
+ }
860
+
796
861
  size_t iter = kUpb_Message_Begin;
797
862
  const upb_DefPool* pool = upb_FileDef_Pool(upb_MessageDef_File(m));
798
863
  const upb_FieldDef* field;
@@ -813,11 +878,13 @@ static VALUE Message_CreateHash(const upb_Message* msg,
813
878
  const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry_m, 1);
814
879
  const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry_m, 2);
815
880
  upb_CType key_type = upb_FieldDef_CType(key_f);
816
- msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f));
881
+ msg_value = Map_CreateHash(val.map_val, key_type, TypeInfo_get(val_f),
882
+ emit_defaults);
817
883
  } else if (upb_FieldDef_IsRepeated(field)) {
818
- msg_value = RepeatedField_CreateArray(val.array_val, type_info);
884
+ msg_value =
885
+ RepeatedField_CreateArray(val.array_val, type_info, emit_defaults);
819
886
  } else {
820
- msg_value = Scalar_CreateHash(val, type_info);
887
+ msg_value = Scalar_CreateHash(val, type_info, emit_defaults);
821
888
  }
822
889
 
823
890
  VALUE msg_key = ID2SYM(rb_intern(upb_FieldDef_Name(field)));
@@ -827,9 +894,11 @@ static VALUE Message_CreateHash(const upb_Message* msg,
827
894
  return hash;
828
895
  }
829
896
 
830
- VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
897
+ VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info,
898
+ bool emit_defaults) {
831
899
  if (type_info.type == kUpb_CType_Message) {
832
- return Message_CreateHash(msgval.msg_val, type_info.def.msgdef);
900
+ return Message_CreateHash(msgval.msg_val, type_info.def.msgdef,
901
+ emit_defaults);
833
902
  } else {
834
903
  return Convert_UpbToRuby(msgval, type_info, Qnil);
835
904
  }
@@ -840,11 +909,49 @@ VALUE Scalar_CreateHash(upb_MessageValue msgval, TypeInfo type_info) {
840
909
  *
841
910
  * Returns the message as a Ruby Hash object, with keys as symbols.
842
911
  *
912
+ * By default, only fields that are present are included. A field without
913
+ * presence (an implicit presence scalar or enum, or a repeated or map field)
914
+ * counts as present only when it holds a non-default value or is non-empty.
915
+ *
916
+ * +emit_defaults+ does not emit a default value for every field. It only
917
+ * additionally includes the fields that have no presence, using their default
918
+ * values (for example 0, "" or false, and empty arrays and hashes for repeated
919
+ * and map fields). This is the ProtoJSON "always emit fields without presence"
920
+ * option, called +always_print_fields_with_no_presence+ in C++ and Python.
921
+ *
922
+ * Fields that have presence are never added by +emit_defaults+ and are
923
+ * included only when they are set: singular message fields, fields in a
924
+ * oneof, and fields with explicit presence such as proto3 +optional+ fields
925
+ * and proto2 singular fields. To include one of these, set it explicitly.
926
+ *
927
+ * The option applies recursively, including to messages in repeated fields
928
+ * and map values. It selects the same fields as #inspect and as .encode_json
929
+ * with +emit_defaults+.
930
+ *
931
+ * @param kwargs [Hash]
932
+ * @option emit_defaults [Boolean] set true to also include fields that have
933
+ * no presence, with their default values (default is false). Fields that have
934
+ * presence are not affected.
843
935
  * @return [Hash]
844
936
  */
845
- static VALUE Message_to_h(VALUE _self) {
937
+ static VALUE Message_to_h(int argc, VALUE* argv, VALUE _self) {
846
938
  Message* self = ruby_to_Message(_self);
847
- return Message_CreateHash(self->msg, self->msgdef);
939
+ VALUE kwargs = Qnil;
940
+ bool emit_defaults = false;
941
+
942
+ rb_scan_args_kw(RB_SCAN_ARGS_PASS_CALLED_KEYWORDS, argc, argv, ":", &kwargs);
943
+
944
+ if (!NIL_P(kwargs)) {
945
+ ID keyword_ids[1];
946
+ VALUE values[1];
947
+ keyword_ids[0] = rb_intern("emit_defaults");
948
+ rb_get_kwargs(kwargs, keyword_ids, 0, 1, values);
949
+ if (values[0] != Qundef) {
950
+ emit_defaults = RTEST(values[0]);
951
+ }
952
+ }
953
+
954
+ return Message_CreateHash(self->msg, self->msgdef, emit_defaults);
848
955
  }
849
956
 
850
957
  /*
@@ -937,8 +1044,10 @@ static VALUE Message_index_set(VALUE _self, VALUE field_name, VALUE value) {
937
1044
  }
938
1045
 
939
1046
  val = Convert_RubyToUpb(value, upb_FieldDef_Name(f), TypeInfo_get(f), arena);
940
- upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val, arena);
941
-
1047
+ if (!upb_Message_SetFieldByDef(Message_GetMutable(_self, NULL), f, val,
1048
+ arena)) {
1049
+ Arena_raise_oom();
1050
+ }
942
1051
  return Qnil;
943
1052
  }
944
1053
 
@@ -995,6 +1104,9 @@ VALUE Message_decode_bytes(size_t size, const char* bytes, int options,
995
1104
  upb_DecodeStatus status = upb_Decode(bytes, size, (upb_Message*)msg->msg,
996
1105
  upb_MessageDef_MiniTable(msg->msgdef),
997
1106
  extreg, options, Arena_get(msg->arena));
1107
+ if (status == kUpb_DecodeStatus_OutOfMemory) {
1108
+ Arena_raise_oom();
1109
+ }
998
1110
  if (status != kUpb_DecodeStatus_Ok) {
999
1111
  rb_raise(cParseError, "Error occurred during parsing");
1000
1112
  }
@@ -1064,10 +1176,18 @@ static VALUE Message_decode_json(int argc, VALUE* argv, VALUE klass) {
1064
1176
  switch (result) {
1065
1177
  case kUpb_JsonDecodeResult_Ok:
1066
1178
  break;
1067
- case kUpb_JsonDecodeResult_Error:
1179
+ case kUpb_JsonDecodeResult_Error: {
1180
+ VALUE pending_err = rb_errinfo();
1181
+ if (!NIL_P(pending_err)) {
1182
+ rb_set_errinfo(Qnil);
1183
+ rb_exc_raise(pending_err);
1184
+ }
1185
+
1068
1186
  rb_raise(cParseError, "Error occurred during parsing: %s",
1069
1187
  upb_Status_ErrorMessage(&status));
1188
+
1070
1189
  break;
1190
+ }
1071
1191
  }
1072
1192
 
1073
1193
  return msg_rb;
@@ -1113,6 +1233,9 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1113
1233
  }
1114
1234
 
1115
1235
  upb_Arena* arena = upb_Arena_New();
1236
+ if (!arena) {
1237
+ Arena_raise_oom();
1238
+ }
1116
1239
 
1117
1240
  upb_EncodeStatus status =
1118
1241
  upb_Encode(msg->msg, upb_MessageDef_MiniTable(msg->msgdef), options,
@@ -1123,10 +1246,18 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1123
1246
  rb_enc_associate(ret, rb_ascii8bit_encoding());
1124
1247
  upb_Arena_Free(arena);
1125
1248
  return ret;
1126
- } else {
1127
- upb_Arena_Free(arena);
1249
+ }
1250
+ upb_Arena_Free(arena);
1251
+ if (status == kUpb_EncodeStatus_OutOfMemory) {
1252
+ Arena_raise_oom();
1253
+ }
1254
+ if (status == kUpb_EncodeStatus_MaxDepthExceeded) {
1128
1255
  rb_raise(rb_eRuntimeError, "Exceeded maximum depth (possibly cycle)");
1129
1256
  }
1257
+ if (status == kUpb_EncodeStatus_MaxSizeExceeded) {
1258
+ rb_raise(rb_eRuntimeError, "Exceeded maximum size");
1259
+ }
1260
+ rb_raise(cParseError, "Unknown encoding error");
1130
1261
  }
1131
1262
 
1132
1263
  /*
@@ -1138,8 +1269,10 @@ static VALUE Message_encode(int argc, VALUE* argv, VALUE klass) {
1138
1269
  * @param options [Hash]
1139
1270
  * @option preserve_proto_fieldnames [Boolean] set true to use original
1140
1271
  * fieldnames (default is to camelCase)
1141
- * @option emit_defaults [Boolean] set true to emit 0/false values (default is
1142
- * to omit them)
1272
+ * @option emit_defaults [Boolean] set true to also emit fields that have no
1273
+ * presence, with their default values (default is to omit them). Fields that
1274
+ * have presence, such as message fields, oneof fields and +optional+ fields,
1275
+ * are emitted only when set. See #to_h.
1143
1276
  * @return [String]
1144
1277
  */
1145
1278
  static VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) {
@@ -1310,9 +1443,15 @@ VALUE build_module_from_enumdesc(VALUE _enumdesc) {
1310
1443
  int n = upb_EnumDef_ValueCount(e);
1311
1444
  for (int i = 0; i < n; i++) {
1312
1445
  const upb_EnumValueDef* ev = upb_EnumDef_Value(e, i);
1313
- upb_Arena* arena = upb_Arena_New();
1314
1446
  const char* src_name = upb_EnumValueDef_Name(ev);
1315
- char* name = upb_strdup2(src_name, strlen(src_name), arena);
1447
+ size_t len = strlen(src_name);
1448
+ upb_Arena* arena = upb_Arena_NewSized(len);
1449
+ if (!arena) Arena_raise_oom();
1450
+ char* name = upb_strdup2(src_name, len, arena);
1451
+ if (!name) {
1452
+ upb_Arena_Free(arena);
1453
+ Arena_raise_oom();
1454
+ }
1316
1455
  int32_t value = upb_EnumValueDef_Number(ev);
1317
1456
  if (name[0] < 'A' || name[0] > 'Z') {
1318
1457
  if (name[0] >= 'a' && name[0] <= 'z') {
@@ -1341,21 +1480,40 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
1341
1480
  upb_Arena* arena) {
1342
1481
  // Serialize and parse.
1343
1482
  upb_Arena* tmp_arena = upb_Arena_New();
1483
+ if (!tmp_arena) {
1484
+ Arena_raise_oom();
1485
+ }
1344
1486
  const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
1345
1487
  size_t size;
1346
1488
 
1347
1489
  upb_Message* new_msg = upb_Message_New(layout, arena);
1490
+ if (!new_msg) {
1491
+ upb_Arena_Free(tmp_arena);
1492
+ Arena_raise_oom();
1493
+ }
1348
1494
  char* data;
1349
1495
 
1350
1496
  const upb_FileDef* file = upb_MessageDef_File(m);
1351
1497
  const upb_ExtensionRegistry* extreg =
1352
1498
  upb_DefPool_ExtensionRegistry(upb_FileDef_Pool(file));
1353
- if (upb_Encode(msg, layout, 0, tmp_arena, &data, &size) !=
1354
- kUpb_EncodeStatus_Ok ||
1355
- upb_Decode(data, size, new_msg, layout, extreg, 0, arena) !=
1356
- kUpb_DecodeStatus_Ok) {
1499
+ upb_EncodeStatus encode_status =
1500
+ upb_Encode(msg, layout, 0, tmp_arena, &data, &size);
1501
+ if (encode_status == kUpb_EncodeStatus_OutOfMemory) {
1502
+ upb_Arena_Free(tmp_arena);
1503
+ Arena_raise_oom();
1504
+ } else if (encode_status != kUpb_EncodeStatus_Ok) {
1357
1505
  upb_Arena_Free(tmp_arena);
1358
- rb_raise(cParseError, "Error occurred copying proto");
1506
+ rb_raise(cParseError, "Error occurred copying proto during encode");
1507
+ }
1508
+
1509
+ upb_DecodeStatus decode_status =
1510
+ upb_Decode(data, size, new_msg, layout, extreg, 0, arena);
1511
+ if (decode_status == kUpb_DecodeStatus_OutOfMemory) {
1512
+ upb_Arena_Free(tmp_arena);
1513
+ Arena_raise_oom();
1514
+ } else if (decode_status != kUpb_DecodeStatus_Ok) {
1515
+ upb_Arena_Free(tmp_arena);
1516
+ rb_raise(cParseError, "Error occurred copying proto during decode");
1359
1517
  }
1360
1518
 
1361
1519
  upb_Arena_Free(tmp_arena);
@@ -1392,8 +1550,10 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1392
1550
  time = rb_time_timespec(value);
1393
1551
  sec.int64_val = time.tv_sec;
1394
1552
  nsec.int32_val = time.tv_nsec;
1395
- upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1396
- upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1553
+ if (!upb_Message_SetFieldByDef(msg, sec_f, sec, arena) ||
1554
+ !upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena)) {
1555
+ Arena_raise_oom();
1556
+ }
1397
1557
  return msg;
1398
1558
  }
1399
1559
  case kUpb_WellKnown_Duration: {
@@ -1408,8 +1568,10 @@ const upb_Message* Message_GetUpbMessage(VALUE value, const upb_MessageDef* m,
1408
1568
 
1409
1569
  sec.int64_val = NUM2LL(value);
1410
1570
  nsec.int32_val = round((NUM2DBL(value) - NUM2LL(value)) * 1000000000);
1411
- upb_Message_SetFieldByDef(msg, sec_f, sec, arena);
1412
- upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena);
1571
+ if (!upb_Message_SetFieldByDef(msg, sec_f, sec, arena) ||
1572
+ !upb_Message_SetFieldByDef(msg, nsec_f, nsec, arena)) {
1573
+ Arena_raise_oom();
1574
+ }
1413
1575
  return msg;
1414
1576
  }
1415
1577
  default:
@@ -1442,7 +1604,7 @@ static void Message_define_class(VALUE klass) {
1442
1604
  rb_define_method(klass, "freeze", Message_freeze, 0);
1443
1605
  rb_define_method(klass, "frozen?", Message_frozen, 0);
1444
1606
  rb_define_method(klass, "hash", Message_hash, 0);
1445
- rb_define_method(klass, "to_h", Message_to_h, 0);
1607
+ rb_define_method(klass, "to_h", Message_to_h, -1);
1446
1608
  rb_define_method(klass, "inspect", Message_inspect, 0);
1447
1609
  rb_define_method(klass, "to_s", Message_inspect, 0);
1448
1610
  rb_define_method(klass, "[]", Message_index, 1);
@@ -58,7 +58,8 @@ upb_Message* Message_deep_copy(const upb_Message* msg, const upb_MessageDef* m,
58
58
  void Message_CheckClass(VALUE klass);
59
59
 
60
60
  // Returns a new Hash object containing the contents of this message.
61
- VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info);
61
+ VALUE Scalar_CreateHash(upb_MessageValue val, TypeInfo type_info,
62
+ bool emit_defaults);
62
63
 
63
64
  // Creates a message class or enum module for this descriptor, respectively.
64
65
  VALUE build_class_from_descriptor(VALUE descriptor);
@@ -182,23 +182,59 @@ const rb_data_type_t Arena_type = {
182
182
  .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
183
183
  };
184
184
 
185
+ struct ruby_upb_xrealloc_args {
186
+ void* ptr;
187
+ size_t size;
188
+ };
189
+
190
+ static VALUE safe_xrealloc_wrapper(VALUE arg) {
191
+ struct ruby_upb_xrealloc_args* args = (struct ruby_upb_xrealloc_args*)arg;
192
+
193
+ // If xrealloc fails, it will longjmp out of this function immediately.
194
+ // If it succeeds, we return the pointer cast as a VALUE.
195
+ void* new_ptr = xrealloc(args->ptr, args->size);
196
+ return (VALUE)new_ptr;
197
+ }
198
+
185
199
  static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize,
186
200
  size_t size, size_t* actual_size) {
187
201
  if (size == 0) {
188
202
  xfree(ptr);
189
203
  return NULL;
190
204
  } else {
191
- return xrealloc(ptr, size);
205
+ struct ruby_upb_xrealloc_args args = {ptr, size};
206
+ int state = 0;
207
+
208
+ void* new_ptr =
209
+ (void*)rb_protect(safe_xrealloc_wrapper, (VALUE)&args, &state);
210
+
211
+ // Exception caught, but rb_errinfo still has the original error for
212
+ // consumption by the caller
213
+ return state ? NULL : new_ptr;
192
214
  }
193
215
  }
194
216
 
195
217
  upb_alloc ruby_upb_alloc = {&ruby_upb_allocfunc};
196
218
 
219
+ void Arena_raise_oom() {
220
+ VALUE pending_err = rb_errinfo();
221
+ if (!NIL_P(pending_err)) {
222
+ rb_set_errinfo(Qnil);
223
+ rb_exc_raise(pending_err);
224
+ }
225
+ rb_raise(rb_eNoMemError, "Failed to allocate arena.");
226
+ }
227
+
197
228
  static VALUE Arena_alloc(VALUE klass) {
198
- Arena* arena = ALLOC(Arena);
199
- arena->arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc);
200
- arena->pinned_objs = Qnil;
201
- return TypedData_Wrap_Struct(klass, &Arena_type, arena);
229
+ Arena* rb_arena = ALLOC(Arena);
230
+ upb_Arena* arena = upb_Arena_Init(NULL, 0, &ruby_upb_alloc);
231
+ if (!arena) {
232
+ xfree(rb_arena);
233
+ Arena_raise_oom();
234
+ }
235
+ rb_arena->arena = arena;
236
+ rb_arena->pinned_objs = Qnil;
237
+ return TypedData_Wrap_Struct(klass, &Arena_type, rb_arena);
202
238
  }
203
239
 
204
240
  upb_Arena* Arena_get(VALUE _arena) {
@@ -317,13 +353,33 @@ VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj) {
317
353
  }
318
354
  }
319
355
 
356
+ static VALUE Google_Protobuf_Internal_allocation_count_is_available(
357
+ VALUE self) {
358
+ return upb_AllocationCount_IsAvailable() ? Qtrue : Qfalse;
359
+ }
360
+
361
+ static VALUE Google_Protobuf_Internal_allocation_count_get(VALUE self) {
362
+ return ULL2NUM(upb_AllocationCount_Get());
363
+ }
364
+
365
+ static VALUE Google_Protobuf_Internal_allocation_count_reset(VALUE self) {
366
+ upb_AllocationCount_Reset();
367
+ return Qnil;
368
+ }
369
+
370
+ static VALUE Google_Protobuf_Internal_allocation_count_fail_on(VALUE self,
371
+ VALUE n) {
372
+ upb_AllocationCount_FailOn(NUM2ULL(n));
373
+ return Qnil;
374
+ }
375
+
320
376
  // -----------------------------------------------------------------------------
321
377
  // Initialization/entry point.
322
378
  // -----------------------------------------------------------------------------
323
379
 
324
380
  // This must be named "Init_protobuf_c" because the Ruby module is named
325
381
  // "protobuf_c" -- the VM looks for this symbol in our .so.
326
- __attribute__((visibility("default"))) void Init_protobuf_c() {
382
+ RUBY_FUNC_EXPORTED void Init_protobuf_c() {
327
383
  VALUE google = rb_define_module("Google");
328
384
  VALUE protobuf = rb_define_module_under(google, "Protobuf");
329
385
 
@@ -343,6 +399,19 @@ __attribute__((visibility("default"))) void Init_protobuf_c() {
343
399
  Google_Protobuf_discard_unknown, 1);
344
400
  rb_define_singleton_method(protobuf, "deep_copy", Google_Protobuf_deep_copy,
345
401
  1);
402
+
403
+ VALUE internal = rb_const_get(protobuf, rb_intern("Internal"));
404
+ rb_define_singleton_method(
405
+ internal, "allocation_count_is_available",
406
+ Google_Protobuf_Internal_allocation_count_is_available, 0);
407
+ rb_define_singleton_method(internal, "allocation_count_get",
408
+ Google_Protobuf_Internal_allocation_count_get, 0);
409
+ rb_define_singleton_method(internal, "allocation_count_reset",
410
+ Google_Protobuf_Internal_allocation_count_reset,
411
+ 0);
412
+ rb_define_singleton_method(internal, "allocation_count_fail_on",
413
+ Google_Protobuf_Internal_allocation_count_fail_on,
414
+ 1);
346
415
  }
347
416
 
348
417
  // -----------------------------------------------------------------------------
@@ -39,6 +39,7 @@ const upb_FieldDef* map_field_value(const upb_FieldDef* field);
39
39
 
40
40
  VALUE Arena_new();
41
41
  upb_Arena* Arena_get(VALUE arena);
42
+ void Arena_raise_oom(void);
42
43
 
43
44
  // Fuses this arena to another, throwing a Ruby exception if this is not
44
45
  // possible.