xref: /aosp_15_r20/external/grpc-grpc/third_party/upb/upb/message/copy.c (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "upb/message/copy.h"
9 
10 #include <stdbool.h>
11 #include <string.h>
12 
13 #include "upb/base/descriptor_constants.h"
14 #include "upb/base/string_view.h"
15 #include "upb/mem/arena.h"
16 #include "upb/message/accessors.h"
17 #include "upb/message/array.h"
18 #include "upb/message/internal/accessors.h"
19 #include "upb/message/internal/array.h"
20 #include "upb/message/internal/extension.h"
21 #include "upb/message/internal/map.h"
22 #include "upb/message/map.h"
23 #include "upb/message/message.h"
24 #include "upb/message/tagged_ptr.h"
25 #include "upb/mini_table/extension.h"
26 #include "upb/mini_table/field.h"
27 #include "upb/mini_table/internal/field.h"
28 #include "upb/mini_table/internal/size_log2.h"
29 #include "upb/mini_table/message.h"
30 #include "upb/mini_table/sub.h"
31 
32 // Must be last.
33 #include "upb/port/def.inc"
34 
upb_Clone_StringView(upb_StringView str,upb_Arena * arena)35 static upb_StringView upb_Clone_StringView(upb_StringView str,
36                                            upb_Arena* arena) {
37   if (str.size == 0) {
38     return upb_StringView_FromDataAndSize(NULL, 0);
39   }
40   void* cloned_data = upb_Arena_Malloc(arena, str.size);
41   upb_StringView cloned_str =
42       upb_StringView_FromDataAndSize(cloned_data, str.size);
43   memcpy(cloned_data, str.data, str.size);
44   return cloned_str;
45 }
46 
upb_Clone_MessageValue(void * value,upb_CType value_type,const upb_MiniTable * sub,upb_Arena * arena)47 static bool upb_Clone_MessageValue(void* value, upb_CType value_type,
48                                    const upb_MiniTable* sub, upb_Arena* arena) {
49   switch (value_type) {
50     case kUpb_CType_Bool:
51     case kUpb_CType_Float:
52     case kUpb_CType_Int32:
53     case kUpb_CType_UInt32:
54     case kUpb_CType_Enum:
55     case kUpb_CType_Double:
56     case kUpb_CType_Int64:
57     case kUpb_CType_UInt64:
58       return true;
59     case kUpb_CType_String:
60     case kUpb_CType_Bytes: {
61       upb_StringView source = *(upb_StringView*)value;
62       int size = source.size;
63       void* cloned_data = upb_Arena_Malloc(arena, size);
64       if (cloned_data == NULL) {
65         return false;
66       }
67       *(upb_StringView*)value =
68           upb_StringView_FromDataAndSize(cloned_data, size);
69       memcpy(cloned_data, source.data, size);
70       return true;
71     } break;
72     case kUpb_CType_Message: {
73       const upb_TaggedMessagePtr source = *(upb_TaggedMessagePtr*)value;
74       bool is_empty = upb_TaggedMessagePtr_IsEmpty(source);
75       if (is_empty) sub = UPB_PRIVATE(_upb_MiniTable_Empty)();
76       UPB_ASSERT(source);
77       upb_Message* clone = upb_Message_DeepClone(
78           UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(source), sub, arena);
79       *(upb_TaggedMessagePtr*)value =
80           UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(clone, is_empty);
81       return clone != NULL;
82     } break;
83   }
84   UPB_UNREACHABLE();
85 }
86 
upb_Map_DeepClone(const upb_Map * map,upb_CType key_type,upb_CType value_type,const upb_MiniTable * map_entry_table,upb_Arena * arena)87 upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type,
88                            upb_CType value_type,
89                            const upb_MiniTable* map_entry_table,
90                            upb_Arena* arena) {
91   upb_Map* cloned_map = _upb_Map_New(arena, map->key_size, map->val_size);
92   if (cloned_map == NULL) {
93     return NULL;
94   }
95   upb_MessageValue key, val;
96   size_t iter = kUpb_Map_Begin;
97   while (upb_Map_Next(map, &key, &val, &iter)) {
98     const upb_MiniTableField* value_field =
99         &map_entry_table->UPB_PRIVATE(fields)[1];
100     const upb_MiniTable* value_sub =
101         upb_MiniTableField_CType(value_field) == kUpb_CType_Message
102             ? upb_MiniTable_GetSubMessageTable(map_entry_table, value_field)
103             : NULL;
104     upb_CType value_field_type = upb_MiniTableField_CType(value_field);
105     if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) {
106       return NULL;
107     }
108     if (!upb_Map_Set(cloned_map, key, val, arena)) {
109       return NULL;
110     }
111   }
112   return cloned_map;
113 }
114 
upb_Message_Map_DeepClone(const upb_Map * map,const upb_MiniTable * mini_table,const upb_MiniTableField * f,upb_Message * clone,upb_Arena * arena)115 static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map,
116                                           const upb_MiniTable* mini_table,
117                                           const upb_MiniTableField* f,
118                                           upb_Message* clone,
119                                           upb_Arena* arena) {
120   // TODO: use a variant of upb_MiniTable_GetSubMessageTable() here.
121   const upb_MiniTable* map_entry_table = upb_MiniTableSub_Message(
122       mini_table->UPB_PRIVATE(subs)[f->UPB_PRIVATE(submsg_index)]);
123   UPB_ASSERT(map_entry_table);
124 
125   const upb_MiniTableField* key_field =
126       &map_entry_table->UPB_PRIVATE(fields)[0];
127   const upb_MiniTableField* value_field =
128       &map_entry_table->UPB_PRIVATE(fields)[1];
129 
130   upb_Map* cloned_map = upb_Map_DeepClone(
131       map, upb_MiniTableField_CType(key_field),
132       upb_MiniTableField_CType(value_field), map_entry_table, arena);
133   if (!cloned_map) {
134     return NULL;
135   }
136   _upb_Message_SetNonExtensionField(clone, f, &cloned_map);
137   return cloned_map;
138 }
139 
upb_Array_DeepClone(const upb_Array * array,upb_CType value_type,const upb_MiniTable * sub,upb_Arena * arena)140 upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type,
141                                const upb_MiniTable* sub, upb_Arena* arena) {
142   const size_t size = array->UPB_PRIVATE(size);
143   const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(value_type);
144   upb_Array* cloned_array = UPB_PRIVATE(_upb_Array_New)(arena, size, lg2);
145   if (!cloned_array) {
146     return NULL;
147   }
148   if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(cloned_array, size, arena)) {
149     return NULL;
150   }
151   for (size_t i = 0; i < size; ++i) {
152     upb_MessageValue val = upb_Array_Get(array, i);
153     if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) {
154       return false;
155     }
156     upb_Array_Set(cloned_array, i, val);
157   }
158   return cloned_array;
159 }
160 
upb_Message_Array_DeepClone(const upb_Array * array,const upb_MiniTable * mini_table,const upb_MiniTableField * field,upb_Message * clone,upb_Arena * arena)161 static bool upb_Message_Array_DeepClone(const upb_Array* array,
162                                         const upb_MiniTable* mini_table,
163                                         const upb_MiniTableField* field,
164                                         upb_Message* clone, upb_Arena* arena) {
165   UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(field);
166   upb_Array* cloned_array = upb_Array_DeepClone(
167       array, upb_MiniTableField_CType(field),
168       upb_MiniTableField_CType(field) == kUpb_CType_Message
169           ? upb_MiniTable_GetSubMessageTable(mini_table, field)
170           : NULL,
171       arena);
172 
173   // Clear out upb_Array* due to parent memcpy.
174   _upb_Message_SetNonExtensionField(clone, field, &cloned_array);
175   return true;
176 }
177 
upb_Clone_ExtensionValue(const upb_MiniTableExtension * mini_table_ext,const upb_Extension * source,upb_Extension * dest,upb_Arena * arena)178 static bool upb_Clone_ExtensionValue(
179     const upb_MiniTableExtension* mini_table_ext, const upb_Extension* source,
180     upb_Extension* dest, upb_Arena* arena) {
181   dest->data = source->data;
182   return upb_Clone_MessageValue(
183       &dest->data,
184       upb_MiniTableField_CType(&mini_table_ext->UPB_PRIVATE(field)),
185       upb_MiniTableExtension_GetSubMessage(mini_table_ext), arena);
186 }
187 
_upb_Message_Copy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * mini_table,upb_Arena * arena)188 upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
189                                const upb_MiniTable* mini_table,
190                                upb_Arena* arena) {
191   upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0);
192   // Only copy message area skipping upb_Message_Internal.
193   memcpy(dst + 1, src + 1, mini_table->UPB_PRIVATE(size) - sizeof(upb_Message));
194   for (size_t i = 0; i < mini_table->UPB_PRIVATE(field_count); ++i) {
195     const upb_MiniTableField* field = &mini_table->UPB_PRIVATE(fields)[i];
196     if (upb_MiniTableField_IsScalar(field)) {
197       switch (upb_MiniTableField_CType(field)) {
198         case kUpb_CType_Message: {
199           upb_TaggedMessagePtr tagged =
200               upb_Message_GetTaggedMessagePtr(src, field, NULL);
201           const upb_Message* sub_message =
202               UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged);
203           if (sub_message != NULL) {
204             // If the message is currently in an unlinked, "empty" state we keep
205             // it that way, because we don't want to deal with decode options,
206             // decode status, or possible parse failure here.
207             bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged);
208             const upb_MiniTable* sub_message_table =
209                 is_empty ? UPB_PRIVATE(_upb_MiniTable_Empty)()
210                          : upb_MiniTable_GetSubMessageTable(mini_table, field);
211             upb_Message* dst_sub_message =
212                 upb_Message_DeepClone(sub_message, sub_message_table, arena);
213             if (dst_sub_message == NULL) {
214               return NULL;
215             }
216             _upb_Message_SetTaggedMessagePtr(
217                 dst, mini_table, field,
218                 UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message,
219                                                         is_empty));
220           }
221         } break;
222         case kUpb_CType_String:
223         case kUpb_CType_Bytes: {
224           upb_StringView str = upb_Message_GetString(src, field, empty_string);
225           if (str.size != 0) {
226             if (!upb_Message_SetString(
227                     dst, field, upb_Clone_StringView(str, arena), arena)) {
228               return NULL;
229             }
230           }
231         } break;
232         default:
233           // Scalar, already copied.
234           break;
235       }
236     } else {
237       if (upb_MiniTableField_IsMap(field)) {
238         const upb_Map* map = upb_Message_GetMap(src, field);
239         if (map != NULL) {
240           if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) {
241             return NULL;
242           }
243         }
244       } else {
245         const upb_Array* array = upb_Message_GetArray(src, field);
246         if (array != NULL) {
247           if (!upb_Message_Array_DeepClone(array, mini_table, field, dst,
248                                            arena)) {
249             return NULL;
250           }
251         }
252       }
253     }
254   }
255   // Clone extensions.
256   size_t ext_count;
257   const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(src, &ext_count);
258   for (size_t i = 0; i < ext_count; ++i) {
259     const upb_Extension* msg_ext = &ext[i];
260     const upb_MiniTableField* field = &msg_ext->ext->UPB_PRIVATE(field);
261     upb_Extension* dst_ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(
262         dst, msg_ext->ext, arena);
263     if (!dst_ext) return NULL;
264     if (upb_MiniTableField_IsScalar(field)) {
265       if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) {
266         return NULL;
267       }
268     } else {
269       upb_Array* msg_array = (upb_Array*)msg_ext->data.ptr;
270       UPB_ASSERT(msg_array);
271       upb_Array* cloned_array = upb_Array_DeepClone(
272           msg_array, upb_MiniTableField_CType(field),
273           upb_MiniTableExtension_GetSubMessage(msg_ext->ext), arena);
274       if (!cloned_array) {
275         return NULL;
276       }
277       dst_ext->data.ptr = (void*)cloned_array;
278     }
279   }
280 
281   // Clone unknowns.
282   size_t unknown_size = 0;
283   const char* ptr = upb_Message_GetUnknown(src, &unknown_size);
284   if (unknown_size != 0) {
285     UPB_ASSERT(ptr);
286     // Make a copy into destination arena.
287     if (!UPB_PRIVATE(_upb_Message_AddUnknown)(dst, ptr, unknown_size, arena)) {
288       return NULL;
289     }
290   }
291   return dst;
292 }
293 
upb_Message_DeepCopy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * mini_table,upb_Arena * arena)294 bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src,
295                           const upb_MiniTable* mini_table, upb_Arena* arena) {
296   upb_Message_Clear(dst, mini_table);
297   return _upb_Message_Copy(dst, src, mini_table, arena) != NULL;
298 }
299 
300 // Deep clones a message using the provided target arena.
301 //
302 // Returns NULL on failure.
upb_Message_DeepClone(const upb_Message * msg,const upb_MiniTable * m,upb_Arena * arena)303 upb_Message* upb_Message_DeepClone(const upb_Message* msg,
304                                    const upb_MiniTable* m, upb_Arena* arena) {
305   upb_Message* clone = upb_Message_New(m, arena);
306   return _upb_Message_Copy(clone, msg, m, arena);
307 }
308 
309 // Performs a shallow copy. TODO: Extend to handle unknown fields.
upb_Message_ShallowCopy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * m)310 void upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src,
311                              const upb_MiniTable* m) {
312   memcpy(dst, src, m->UPB_PRIVATE(size));
313 }
314 
315 // Performs a shallow clone. Ignores unknown fields.
upb_Message_ShallowClone(const upb_Message * msg,const upb_MiniTable * m,upb_Arena * arena)316 upb_Message* upb_Message_ShallowClone(const upb_Message* msg,
317                                       const upb_MiniTable* m,
318                                       upb_Arena* arena) {
319   upb_Message* clone = upb_Message_New(m, arena);
320   upb_Message_ShallowCopy(clone, msg, m);
321   return clone;
322 }
323