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