• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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         upb_MiniTable_MapValue(map_entry_table);
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   UPB_ASSERT(!upb_Message_IsFrozen(clone));
121   const upb_MiniTable* map_entry_table =
122       upb_MiniTable_MapEntrySubMessage(mini_table, f);
123   UPB_ASSERT(map_entry_table);
124 
125   const upb_MiniTableField* key_field = upb_MiniTable_MapKey(map_entry_table);
126   const upb_MiniTableField* value_field =
127       upb_MiniTable_MapValue(map_entry_table);
128 
129   upb_Map* cloned_map = upb_Map_DeepClone(
130       map, upb_MiniTableField_CType(key_field),
131       upb_MiniTableField_CType(value_field), map_entry_table, arena);
132   if (!cloned_map) {
133     return NULL;
134   }
135   upb_Message_SetBaseField(clone, f, &cloned_map);
136   return cloned_map;
137 }
138 
upb_Array_DeepClone(const upb_Array * array,upb_CType value_type,const upb_MiniTable * sub,upb_Arena * arena)139 upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type,
140                                const upb_MiniTable* sub, upb_Arena* arena) {
141   const size_t size = upb_Array_Size(array);
142   const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(value_type);
143   upb_Array* cloned_array = UPB_PRIVATE(_upb_Array_New)(arena, size, lg2);
144   if (!cloned_array) {
145     return NULL;
146   }
147   if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(cloned_array, size, arena)) {
148     return NULL;
149   }
150   for (size_t i = 0; i < size; ++i) {
151     upb_MessageValue val = upb_Array_Get(array, i);
152     if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) {
153       return false;
154     }
155     upb_Array_Set(cloned_array, i, val);
156   }
157   return cloned_array;
158 }
159 
upb_Message_Array_DeepClone(const upb_Array * array,const upb_MiniTable * mini_table,const upb_MiniTableField * field,upb_Message * clone,upb_Arena * arena)160 static bool upb_Message_Array_DeepClone(const upb_Array* array,
161                                         const upb_MiniTable* mini_table,
162                                         const upb_MiniTableField* field,
163                                         upb_Message* clone, upb_Arena* arena) {
164   UPB_ASSERT(!upb_Message_IsFrozen(clone));
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_SetBaseField(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, upb_MiniTableExtension_CType(mini_table_ext),
184       upb_MiniTableExtension_GetSubMessage(mini_table_ext), arena);
185 }
186 
_upb_Message_Copy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * mini_table,upb_Arena * arena)187 upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src,
188                                const upb_MiniTable* mini_table,
189                                upb_Arena* arena) {
190   UPB_ASSERT(!upb_Message_IsFrozen(dst));
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 (int i = 0; i < upb_MiniTable_FieldCount(mini_table); ++i) {
195     const upb_MiniTableField* field =
196         upb_MiniTable_GetFieldByIndex(mini_table, i);
197     if (upb_MiniTableField_IsScalar(field)) {
198       switch (upb_MiniTableField_CType(field)) {
199         case kUpb_CType_Message: {
200           upb_TaggedMessagePtr tagged =
201               upb_Message_GetTaggedMessagePtr(src, field, NULL);
202           const upb_Message* sub_message =
203               UPB_PRIVATE(_upb_TaggedMessagePtr_GetMessage)(tagged);
204           if (sub_message != NULL) {
205             // If the message is currently in an unlinked, "empty" state we keep
206             // it that way, because we don't want to deal with decode options,
207             // decode status, or possible parse failure here.
208             bool is_empty = upb_TaggedMessagePtr_IsEmpty(tagged);
209             const upb_MiniTable* sub_message_table =
210                 is_empty ? UPB_PRIVATE(_upb_MiniTable_Empty)()
211                          : upb_MiniTable_GetSubMessageTable(mini_table, field);
212             upb_Message* dst_sub_message =
213                 upb_Message_DeepClone(sub_message, sub_message_table, arena);
214             if (dst_sub_message == NULL) {
215               return NULL;
216             }
217             UPB_PRIVATE(_upb_Message_SetTaggedMessagePtr)
218             (dst, field,
219              UPB_PRIVATE(_upb_TaggedMessagePtr_Pack)(dst_sub_message,
220                                                      is_empty));
221           }
222         } break;
223         case kUpb_CType_String:
224         case kUpb_CType_Bytes: {
225           upb_StringView str = upb_Message_GetString(src, field, empty_string);
226           if (str.size != 0) {
227             if (!upb_Message_SetString(
228                     dst, field, upb_Clone_StringView(str, arena), arena)) {
229               return NULL;
230             }
231           }
232         } break;
233         default:
234           // Scalar, already copied.
235           break;
236       }
237     } else {
238       if (upb_MiniTableField_IsMap(field)) {
239         const upb_Map* map = upb_Message_GetMap(src, field);
240         if (map != NULL) {
241           if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) {
242             return NULL;
243           }
244         }
245       } else {
246         const upb_Array* array = upb_Message_GetArray(src, field);
247         if (array != NULL) {
248           if (!upb_Message_Array_DeepClone(array, mini_table, field, dst,
249                                            arena)) {
250             return NULL;
251           }
252         }
253       }
254     }
255   }
256   // Clone extensions.
257   size_t ext_count;
258   const upb_Extension* ext = UPB_PRIVATE(_upb_Message_Getexts)(src, &ext_count);
259   for (size_t i = 0; i < ext_count; ++i) {
260     const upb_Extension* msg_ext = &ext[i];
261     const upb_MiniTableField* field = &msg_ext->ext->UPB_PRIVATE(field);
262     upb_Extension* dst_ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(
263         dst, msg_ext->ext, arena);
264     if (!dst_ext) return NULL;
265     if (upb_MiniTableField_IsScalar(field)) {
266       if (!upb_Clone_ExtensionValue(msg_ext->ext, msg_ext, dst_ext, arena)) {
267         return NULL;
268       }
269     } else {
270       upb_Array* msg_array = (upb_Array*)msg_ext->data.array_val;
271       UPB_ASSERT(msg_array);
272       upb_Array* cloned_array = upb_Array_DeepClone(
273           msg_array, upb_MiniTableField_CType(field),
274           upb_MiniTableExtension_GetSubMessage(msg_ext->ext), arena);
275       if (!cloned_array) {
276         return NULL;
277       }
278       dst_ext->data.array_val = cloned_array;
279     }
280   }
281 
282   // Clone unknowns.
283   size_t unknown_size = 0;
284   const char* ptr = upb_Message_GetUnknown(src, &unknown_size);
285   if (unknown_size != 0) {
286     UPB_ASSERT(ptr);
287     // Make a copy into destination arena.
288     if (!UPB_PRIVATE(_upb_Message_AddUnknown)(dst, ptr, unknown_size, arena)) {
289       return NULL;
290     }
291   }
292   return dst;
293 }
294 
upb_Message_DeepCopy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * mini_table,upb_Arena * arena)295 bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src,
296                           const upb_MiniTable* mini_table, upb_Arena* arena) {
297   UPB_ASSERT(!upb_Message_IsFrozen(dst));
298   upb_Message_Clear(dst, mini_table);
299   return _upb_Message_Copy(dst, src, mini_table, arena) != NULL;
300 }
301 
302 // Deep clones a message using the provided target arena.
303 //
304 // Returns NULL on failure.
upb_Message_DeepClone(const upb_Message * msg,const upb_MiniTable * m,upb_Arena * arena)305 upb_Message* upb_Message_DeepClone(const upb_Message* msg,
306                                    const upb_MiniTable* m, upb_Arena* arena) {
307   upb_Message* clone = upb_Message_New(m, arena);
308   return _upb_Message_Copy(clone, msg, m, arena);
309 }
310 
311 // Performs a shallow copy. TODO: Extend to handle unknown fields.
upb_Message_ShallowCopy(upb_Message * dst,const upb_Message * src,const upb_MiniTable * m)312 void upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src,
313                              const upb_MiniTable* m) {
314   UPB_ASSERT(!upb_Message_IsFrozen(dst));
315   memcpy(dst, src, m->UPB_PRIVATE(size));
316 }
317 
318 // Performs a shallow clone. Ignores unknown fields.
upb_Message_ShallowClone(const upb_Message * msg,const upb_MiniTable * m,upb_Arena * arena)319 upb_Message* upb_Message_ShallowClone(const upb_Message* msg,
320                                       const upb_MiniTable* m,
321                                       upb_Arena* arena) {
322   upb_Message* clone = upb_Message_New(m, arena);
323   upb_Message_ShallowCopy(clone, msg, m);
324   return clone;
325 }
326