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