compare.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2021, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of Google LLC nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include "upb/util/compare.h"
29 
30 #include <setjmp.h>
31 #include <stdbool.h>
32 
33 #include "upb/port_def.inc"
34 
35 struct upb_UnknownFields;
37 
38 typedef struct {
40  union {
46  } data;
48 
50  size_t size;
51  size_t capacity;
53 };
54 
55 typedef struct {
56  const char* end;
59  size_t tmp_size;
60  int depth;
61  jmp_buf err;
63 
68  size_t old = (*ptr - *base);
69  size_t new = UPB_MAX(4, old * 2);
70 
71  *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base),
72  new * sizeof(**base));
74 
75  *ptr = *base + old;
76  *end = *base + new;
77 }
78 
79 static const char* upb_UnknownFields_ParseVarint(const char* ptr,
80  const char* limit,
81  uint64_t* val) {
82  uint8_t byte;
83  int bitpos = 0;
84  *val = 0;
85 
86  do {
87  // Unknown field data must be valid.
88  UPB_ASSERT(bitpos < 70 && ptr < limit);
89  byte = *ptr;
90  *val |= (uint64_t)(byte & 0x7F) << bitpos;
91  ptr++;
92  bitpos += 7;
93  } while (byte & 0x80);
94 
95  return ptr;
96 }
97 
98 // We have to implement our own sort here, since qsort() is not an in-order
99 // sort. Here we use merge sort, the simplest in-order sort.
101  size_t mid, size_t end,
103  memcpy(tmp, &arr[start], (end - start) * sizeof(*tmp));
104 
105  upb_UnknownField* ptr1 = tmp;
106  upb_UnknownField* end1 = &tmp[mid - start];
107  upb_UnknownField* ptr2 = &tmp[mid - start];
108  upb_UnknownField* end2 = &tmp[end - start];
109  upb_UnknownField* out = &arr[start];
110 
111  while (ptr1 < end1 && ptr2 < end2) {
112  if (ptr1->tag <= ptr2->tag) {
113  *out++ = *ptr1++;
114  } else {
115  *out++ = *ptr2++;
116  }
117  }
118 
119  if (ptr1 < end1) {
120  memcpy(out, ptr1, (end1 - ptr1) * sizeof(*out));
121  } else if (ptr2 < end2) {
122  memcpy(out, ptr1, (end2 - ptr2) * sizeof(*out));
123  }
124 }
125 
127  size_t end, upb_UnknownField* tmp) {
128  if (end - start > 1) {
129  size_t mid = start + ((end - start) / 2);
132  upb_UnknownFields_Merge(arr, start, mid, end, tmp);
133  }
134 }
135 
138  if (ctx->tmp_size < fields->size) {
139  ctx->tmp_size = UPB_MAX(8, ctx->tmp_size);
140  while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2;
141  ctx->tmp = realloc(ctx->tmp, ctx->tmp_size * sizeof(*ctx->tmp));
142  }
143  upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp);
144 }
145 
147  upb_UnknownField_Context* ctx, const char** buf) {
148  upb_UnknownField* arr_base = NULL;
149  upb_UnknownField* arr_ptr = NULL;
150  upb_UnknownField* arr_end = NULL;
151  const char* ptr = *buf;
152  uint32_t last_tag = 0;
153  bool sorted = true;
154  while (ptr < ctx->end) {
155  uint64_t tag;
158  int wire_type = tag & 7;
159  if (wire_type == kUpb_WireType_EndGroup) break;
160  if (tag < last_tag) sorted = false;
161  last_tag = tag;
162 
163  if (arr_ptr == arr_end) {
164  upb_UnknownFields_Grow(ctx, &arr_base, &arr_ptr, &arr_end);
165  }
166  upb_UnknownField* field = arr_ptr;
167  field->tag = tag;
168  arr_ptr++;
169 
170  switch (wire_type) {
172  ptr = upb_UnknownFields_ParseVarint(ptr, ctx->end, &field->data.varint);
173  break;
174  case kUpb_WireType_64Bit:
175  UPB_ASSERT(ctx->end - ptr >= 8);
176  memcpy(&field->data.uint64, ptr, 8);
177  ptr += 8;
178  break;
179  case kUpb_WireType_32Bit:
180  UPB_ASSERT(ctx->end - ptr >= 4);
181  memcpy(&field->data.uint32, ptr, 4);
182  ptr += 4;
183  break;
185  uint64_t size;
187  UPB_ASSERT(ctx->end - ptr >= size);
188  field->data.delimited.data = ptr;
189  field->data.delimited.size = size;
190  ptr += size;
191  break;
192  }
194  if (--ctx->depth == 0) {
196  }
197  field->data.group = upb_UnknownFields_DoBuild(ctx, &ptr);
198  ctx->depth++;
199  break;
200  default:
201  UPB_UNREACHABLE();
202  }
203  }
204 
205  *buf = ptr;
208  ret->fields = arr_base;
209  ret->size = arr_ptr - arr_base;
210  ret->capacity = arr_end - arr_base;
211  if (!sorted) {
213  }
214  return ret;
215 }
216 
217 // Builds a upb_UnknownFields data structure from the binary data in buf.
219  const char* buf,
220  size_t size) {
221  ctx->end = buf + size;
223  UPB_ASSERT(buf == ctx->end);
224  return fields;
225 }
226 
227 // Compares two sorted upb_UnknwonFields structures for equality.
229  const upb_UnknownFields* uf2) {
230  if (uf1->size != uf2->size) return false;
231  for (size_t i = 0, n = uf1->size; i < n; i++) {
232  upb_UnknownField* f1 = &uf1->fields[i];
233  upb_UnknownField* f2 = &uf2->fields[i];
234  if (f1->tag != f2->tag) return false;
235  int wire_type = f1->tag & 7;
236  switch (wire_type) {
238  if (f1->data.varint != f2->data.varint) return false;
239  break;
240  case kUpb_WireType_64Bit:
241  if (f1->data.uint64 != f2->data.uint64) return false;
242  break;
243  case kUpb_WireType_32Bit:
244  if (f1->data.uint32 != f2->data.uint32) return false;
245  break;
247  if (!upb_StringView_IsEqual(f1->data.delimited, f2->data.delimited)) {
248  return false;
249  }
250  break;
252  if (!upb_UnknownFields_IsEqual(f1->data.group, f2->data.group)) {
253  return false;
254  }
255  break;
256  default:
257  UPB_UNREACHABLE();
258  }
259  }
260  return true;
261 }
262 
264  size_t size1,
265  const char* buf2,
266  size_t size2,
267  int max_depth) {
268  if (size1 == 0 && size2 == 0) return kUpb_UnknownCompareResult_Equal;
269  if (size1 == 0 || size2 == 0) return kUpb_UnknownCompareResult_NotEqual;
270  if (memcmp(buf1, buf2, size1) == 0) return kUpb_UnknownCompareResult_Equal;
271 
273  .arena = upb_Arena_New(),
274  .depth = max_depth,
275  .tmp = NULL,
276  .tmp_size = 0,
277  };
278 
280 
281  int ret = UPB_SETJMP(ctx.err);
282 
283  if (UPB_LIKELY(ret == 0)) {
284  // First build both unknown fields into a sorted data structure (similar
285  // to the UnknownFieldSet in C++).
286  upb_UnknownFields* uf1 = upb_UnknownFields_Build(&ctx, buf1, size1);
288 
289  // Now perform the equality check on the sorted structures.
290  if (upb_UnknownFields_IsEqual(uf1, uf2)) {
292  } else {
294  }
295  }
296 
298  free(ctx.tmp);
299  return ret;
300 }
kUpb_UnknownCompareResult_NotEqual
@ kUpb_UnknownCompareResult_NotEqual
Definition: upb/upb/util/compare.h:51
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
kUpb_WireType_Delimited
@ kUpb_WireType_Delimited
Definition: upb/upb/upb.h:277
ctx::arena
upb_Arena * arena
Definition: conformance_upb.c:84
upb_UnknownFields_Build
static upb_UnknownFields * upb_UnknownFields_Build(upb_UnknownField_Context *ctx, const char *buf, size_t size)
Definition: compare.c:218
upb_UnknownField_Context::end
const char * end
Definition: compare.c:56
upb_UnknownFields_Sort
static void upb_UnknownFields_Sort(upb_UnknownField_Context *ctx, upb_UnknownFields *fields)
Definition: compare.c:136
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
upb_UnknownFields::capacity
size_t capacity
Definition: compare.c:51
upb_Arena_Realloc
UPB_INLINE void * upb_Arena_Realloc(upb_Arena *a, void *ptr, size_t oldsize, size_t size)
Definition: upb/upb/upb.h:246
ctx
Definition: benchmark-async.c:30
upb_UnknownCompareResult
upb_UnknownCompareResult
Definition: upb/upb/util/compare.h:49
upb_UnknownFields::size
size_t size
Definition: compare.c:50
xds_manager.f1
f1
Definition: xds_manager.py:42
upb_UnknownField_Context::tmp
upb_UnknownField * tmp
Definition: compare.c:58
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
UPB_UNREACHABLE
#define UPB_UNREACHABLE()
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:145
UINT32_MAX
#define UINT32_MAX
Definition: stdint-msvc2008.h:142
UPB_SETJMP
#define UPB_SETJMP(buf)
Definition: php-upb.c:163
upb_UnknownField_Context::tmp_size
size_t tmp_size
Definition: compare.c:59
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
kUpb_UnknownCompareResult_Equal
@ kUpb_UnknownCompareResult_Equal
Definition: upb/upb/util/compare.h:50
upb_Arena_New
UPB_INLINE upb_Arena * upb_Arena_New(void)
Definition: upb/upb/upb.h:267
upb_UnknownFields_ParseVarint
static const char * upb_UnknownFields_ParseVarint(const char *ptr, const char *limit, uint64_t *val)
Definition: compare.c:79
upb_UnknownField::group
upb_UnknownFields * group
Definition: compare.c:45
upb_UnknownFields_DoBuild
static upb_UnknownFields * upb_UnknownFields_DoBuild(upb_UnknownField_Context *ctx, const char **buf)
Definition: compare.c:146
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
upb_UnknownField_Context::arena
upb_Arena * arena
Definition: compare.c:57
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
start
static uint64_t start
Definition: benchmark-pound.c:74
kUpb_WireType_EndGroup
@ kUpb_WireType_EndGroup
Definition: upb/upb/upb.h:279
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
tag
static void * tag(intptr_t t)
Definition: bad_client.cc:318
upb_UnknownFields_Grow
static void upb_UnknownFields_Grow(upb_UnknownField_Context *ctx, upb_UnknownField **base, upb_UnknownField **ptr, upb_UnknownField **end)
Definition: compare.c:64
upb_Arena_Malloc
UPB_INLINE void * upb_Arena_Malloc(upb_Arena *a, size_t size)
Definition: upb/upb/upb.h:222
kUpb_WireType_Varint
@ kUpb_WireType_Varint
Definition: upb/upb/upb.h:275
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
upb_UnknownField
Definition: compare.c:38
upb_UnknownFields_IsEqual
static bool upb_UnknownFields_IsEqual(const upb_UnknownFields *uf1, const upb_UnknownFields *uf2)
Definition: compare.c:228
UPB_ASSERT
#define UPB_ASSERT(expr)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:135
gen_synthetic_protos.base
base
Definition: gen_synthetic_protos.py:31
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
upb_UnknownField_Context::err
jmp_buf err
Definition: compare.c:61
upb_UnknownFields
Definition: compare.c:49
upb_StringView_IsEqual
UPB_INLINE bool upb_StringView_IsEqual(upb_StringView a, upb_StringView b)
Definition: upb/upb/upb.h:89
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
upb_UnknownField::delimited
upb_StringView delimited
Definition: compare.c:44
UPB_MAX
#define UPB_MAX(x, y)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:125
ares::byte
unsigned char byte
Definition: ares-test.h:33
field
const FieldDescriptor * field
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/parser_unittest.cc:2692
kUpb_WireType_32Bit
@ kUpb_WireType_32Bit
Definition: upb/upb/upb.h:280
upb_StringView
Definition: upb/upb/upb.h:72
UPB_LIKELY
#define UPB_LIKELY(x)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:61
upb_UnknownFields_Merge
static void upb_UnknownFields_Merge(upb_UnknownField *arr, size_t start, size_t mid, size_t end, upb_UnknownField *tmp)
Definition: compare.c:100
upb_UnknownField::tag
uint32_t tag
Definition: compare.c:39
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
profile_analyzer.fields
list fields
Definition: profile_analyzer.py:266
upb_UnknownFields::fields
upb_UnknownField * fields
Definition: compare.c:52
compare.h
kUpb_UnknownCompareResult_MaxDepthExceeded
@ kUpb_UnknownCompareResult_MaxDepthExceeded
Definition: upb/upb/util/compare.h:53
upb_UnknownField::uint32
uint32_t uint32
Definition: compare.c:43
buf2
static char buf2[32]
Definition: test-fs.c:127
upb_UnknownField_Context::depth
int depth
Definition: compare.c:60
upb_UnknownField_Context
Definition: compare.c:55
xds_manager.f2
f2
Definition: xds_manager.py:85
autogen_x86imm.tmp
tmp
Definition: autogen_x86imm.py:12
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
upb_Message_UnknownFieldsAreEqual
upb_UnknownCompareResult upb_Message_UnknownFieldsAreEqual(const char *buf1, size_t size1, const char *buf2, size_t size2, int max_depth)
Definition: compare.c:263
kUpb_UnknownCompareResult_OutOfMemory
@ kUpb_UnknownCompareResult_OutOfMemory
Definition: upb/upb/util/compare.h:52
upb_UnknownFields_SortRecursive
static void upb_UnknownFields_SortRecursive(upb_UnknownField *arr, size_t start, size_t end, upb_UnknownField *tmp)
Definition: compare.c:126
upb_UnknownField::varint
uint64_t varint
Definition: compare.c:41
upb_Arena
Definition: upb_internal.h:36
binary_size.old
string old
Definition: binary_size.py:128
upb_Arena_Free
void upb_Arena_Free(upb_Arena *a)
Definition: upb/upb/upb.c:273
UPB_LONGJMP
#define UPB_LONGJMP(buf, val)
Definition: php-upb.c:164
kUpb_WireType_64Bit
@ kUpb_WireType_64Bit
Definition: upb/upb/upb.h:276
kUpb_WireType_StartGroup
@ kUpb_WireType_StartGroup
Definition: upb/upb/upb.h:278
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
upb_UnknownField::uint64
uint64_t uint64
Definition: compare.c:42


grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:52