required_fields.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 
29 
30 #include <inttypes.h>
31 #include <setjmp.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 
35 #include "upb/reflection.h"
36 
37 // Must be last.
38 #include "upb/port_def.inc"
39 
41 // upb_FieldPath_ToText()
43 
44 typedef struct {
45  char* buf;
46  char* ptr;
47  char* end;
48  size_t overflow;
50 
51 UPB_PRINTF(2, 3)
52 static void upb_FieldPath_Printf(upb_PrintfAppender* a, const char* fmt, ...) {
53  size_t n;
54  size_t have = a->end - a->ptr;
55  va_list args;
56 
57  va_start(args, fmt);
58  n = vsnprintf(a->ptr, have, fmt, args);
59  va_end(args);
60 
61  if (UPB_LIKELY(have > n)) {
62  // We can't end up here if the user passed (NULL, 0), therefore ptr is known
63  // to be non-NULL, and UPB_PTRADD() is not necessary.
64  assert(a->ptr);
65  a->ptr += n;
66  } else {
67  a->ptr = UPB_PTRADD(a->ptr, have);
68  a->overflow += (n - have);
69  }
70 }
71 
73  size_t ret = d->ptr - d->buf + d->overflow;
74 
75  if (size > 0) {
76  if (d->ptr == d->end) d->ptr--;
77  *d->ptr = '\0';
78  }
79 
80  return ret;
81 }
82 
84  upb_MessageValue map_key,
85  const upb_FieldDef* key_f) {
86  switch (upb_FieldDef_CType(key_f)) {
87  case kUpb_CType_Int32:
88  upb_FieldPath_Printf(a, "[%" PRId32 "]", map_key.int32_val);
89  break;
90  case kUpb_CType_Int64:
91  upb_FieldPath_Printf(a, "[%" PRId64 "]", map_key.int64_val);
92  break;
93  case kUpb_CType_UInt32:
94  upb_FieldPath_Printf(a, "[%" PRIu32 "]", map_key.uint32_val);
95  break;
96  case kUpb_CType_UInt64:
97  upb_FieldPath_Printf(a, "[%" PRIu64 "]", map_key.uint64_val);
98  break;
99  case kUpb_CType_Bool:
100  upb_FieldPath_Printf(a, "[%s]", map_key.bool_val ? "true" : "false");
101  break;
102  case kUpb_CType_String:
103  upb_FieldPath_Printf(a, "[\"");
104  for (size_t i = 0; i < map_key.str_val.size; i++) {
105  char ch = map_key.str_val.data[i];
106  if (ch == '"') {
107  upb_FieldPath_Printf(a, "\\\"");
108  } else {
109  upb_FieldPath_Printf(a, "%c", ch);
110  }
111  }
112  upb_FieldPath_Printf(a, "\"]");
113  break;
114  default:
115  UPB_UNREACHABLE(); // Other types can't be map keys.
116  }
117 }
118 
121  upb_PrintfAppender appender;
122  appender.buf = buf;
123  appender.ptr = buf;
124  appender.end = UPB_PTRADD(buf, size);
125  appender.overflow = 0;
126  bool first = true;
127 
128  while (ptr->field) {
129  const upb_FieldDef* f = ptr->field;
130 
131  upb_FieldPath_Printf(&appender, first ? "%s" : ".%s", upb_FieldDef_Name(f));
132  first = false;
133  ptr++;
134 
135  if (upb_FieldDef_IsMap(f)) {
136  const upb_FieldDef* key_f =
138  upb_FieldPath_PutMapKey(&appender, ptr->map_key, key_f);
139  ptr++;
140  } else if (upb_FieldDef_IsRepeated(f)) {
141  upb_FieldPath_Printf(&appender, "[%zu]", ptr->array_index);
142  ptr++;
143  }
144  }
145 
146  // Advance beyond terminating NULL.
147  ptr++;
148  *path = ptr;
149  return upb_FieldPath_NullTerminate(&appender, size);
150 }
151 
153 // upb_util_HasUnsetRequired()
155 
156 typedef struct {
158  size_t size;
159  size_t cap;
161 
162 typedef struct {
166  jmp_buf err;
170 
172  vec->path = NULL;
173  vec->size = 0;
174  vec->cap = 0;
175 }
176 
178  upb_FieldPathVector* vec,
179  size_t elems) {
180  if (vec->cap - vec->size < elems) {
181  size_t need = vec->size + elems;
182  vec->cap = UPB_MAX(4, vec->cap);
183  while (vec->cap < need) vec->cap *= 2;
184  vec->path = realloc(vec->path, vec->cap * sizeof(*vec->path));
185  if (!vec->path) {
186  UPB_LONGJMP(ctx->err, 1);
187  }
188  }
189 }
190 
192  if (!ctx->save_paths) return;
193  upb_FieldPathVector_Reserve(ctx, &ctx->stack, 1);
194  ctx->stack.path[ctx->stack.size++] = ent;
195 }
196 
198  if (!ctx->save_paths) return;
199  assert(ctx->stack.size != 0);
200  ctx->stack.size--;
201 }
202 
204  const upb_Message* msg,
205  const upb_MessageDef* m) {
206  // Iterate over all fields to see if any required fields are missing.
207  for (int i = 0, n = upb_MessageDef_FieldCount(m); i < n; i++) {
209  if (upb_FieldDef_Label(f) != kUpb_Label_Required) continue;
210 
211  if (!msg || !upb_Message_Has(msg, f)) {
212  // A required field is missing.
213  ctx->has_unset_required = true;
214 
215  if (ctx->save_paths) {
216  // Append the contents of the stack to the out array, then
217  // NULL-terminate.
218  upb_FieldPathVector_Reserve(ctx, &ctx->out_fields, ctx->stack.size + 2);
219  if (ctx->stack.size) {
220  memcpy(&ctx->out_fields.path[ctx->out_fields.size], ctx->stack.path,
221  ctx->stack.size * sizeof(*ctx->stack.path));
222  }
223  ctx->out_fields.size += ctx->stack.size;
224  ctx->out_fields.path[ctx->out_fields.size++] =
225  (upb_FieldPathEntry){.field = f};
226  ctx->out_fields.path[ctx->out_fields.size++] =
227  (upb_FieldPathEntry){.field = NULL};
228  }
229  }
230  }
231 }
232 
234  const upb_Message* msg,
235  const upb_MessageDef* m) {
236  // OPT: add markers in the schema for where we can avoid iterating:
237  // 1. messages with no required fields.
238  // 2. messages that cannot possibly reach any required fields.
239 
241  if (!msg) return;
242 
243  // Iterate over all present fields to find sub-messages that might be missing
244  // required fields. This may revisit some of the fields already inspected
245  // in the previous loop. We do this separately because this loop will also
246  // find present extensions, which the previous loop will not.
247  //
248  // TODO(haberman): consider changing upb_Message_Next() to be capable of
249  // visiting extensions only, for example with a kUpb_Message_BeginEXT
250  // constant.
251  size_t iter = kUpb_Message_Begin;
252  const upb_FieldDef* f;
253  upb_MessageValue val;
254  while (upb_Message_Next(msg, m, ctx->ext_pool, &f, &val, &iter)) {
255  // Skip non-submessage fields.
256  if (!upb_FieldDef_IsSubMessage(f)) continue;
257 
260 
261  if (upb_FieldDef_IsMap(f)) {
262  // Map field.
263  const upb_FieldDef* val_f = upb_MessageDef_Field(sub_m, 1);
264  const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f);
265  if (!val_m) continue;
266  const upb_Map* map = val.map_val;
267  size_t iter = kUpb_Map_Begin;
268  while (upb_MapIterator_Next(map, &iter)) {
274  }
275  } else if (upb_FieldDef_IsRepeated(f)) {
276  // Repeated field.
277  const upb_Array* arr = val.array_val;
278  for (size_t i = 0, n = upb_Array_Size(arr); i < n; i++) {
280  upb_FindContext_Push(ctx, (upb_FieldPathEntry){.array_index = i});
283  }
284  } else {
285  // Scalar sub-message field.
287  }
288 
290  }
291 }
292 
294  const upb_DefPool* ext_pool,
297  ctx.has_unset_required = false;
298  ctx.save_paths = fields != NULL;
299  ctx.ext_pool = ext_pool;
301  upb_FieldPathVector_Init(&ctx.out_fields);
303  free(ctx.stack.path);
304  if (fields) {
305  upb_FieldPathVector_Reserve(&ctx, &ctx.out_fields, 1);
306  ctx.out_fields.path[ctx.out_fields.size] =
307  (upb_FieldPathEntry){.field = NULL};
308  *fields = ctx.out_fields.path;
309  }
310  return ctx.has_unset_required;
311 }
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
upb_FieldPathEntry
Definition: required_fields.h:52
upb_MessageValue::uint32_val
uint32_t uint32_val
Definition: upb/upb/reflection.h:46
kUpb_CType_String
@ kUpb_CType_String
Definition: upb/upb/upb.h:296
upb_MapIterator_Key
upb_MessageValue upb_MapIterator_Key(const upb_Map *map, size_t iter)
Definition: reflection.c:461
upb_MessageValue::int64_val
int64_t int64_val
Definition: upb/upb/reflection.h:45
kUpb_CType_UInt32
@ kUpb_CType_UInt32
Definition: upb/upb/upb.h:290
upb_FindContext::ext_pool
const upb_DefPool * ext_pool
Definition: required_fields.c:165
vsnprintf
int __cdecl vsnprintf(char *buffer, size_t count, const char *format, va_list argptr)
Definition: libc.cpp:135
kUpb_CType_Int32
@ kUpb_CType_Int32
Definition: upb/upb/upb.h:289
ctx
Definition: benchmark-async.c:30
const
#define const
Definition: bloaty/third_party/zlib/zconf.h:230
kUpb_Map_Begin
#define kUpb_Map_Begin
Definition: upb/upb/upb.h:329
upb_FindContext::out_fields
upb_FieldPathVector out_fields
Definition: required_fields.c:164
upb_StringView::data
const char * data
Definition: upb/upb/upb.h:73
upb_MessageDef
Definition: upb/upb/def.c:100
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
elem
Timer elem
Definition: event_engine/iomgr_event_engine/timer_heap_test.cc:109
UPB_UNREACHABLE
#define UPB_UNREACHABLE()
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:145
upb_MessageValue::str_val
upb_StringView str_val
Definition: upb/upb/reflection.h:51
ctx
static struct test_ctx ctx
Definition: test-ipc-send-recv.c:65
check_documentation.path
path
Definition: check_documentation.py:57
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
upb_MessageValue::int32_val
int32_t int32_val
Definition: upb/upb/reflection.h:44
upb_Array_Get
upb_MessageValue upb_Array_Get(const upb_Array *arr, size_t i)
Definition: reflection.c:364
upb_FieldPathVector_Reserve
static void upb_FieldPathVector_Reserve(upb_FindContext *ctx, upb_FieldPathVector *vec, size_t elems)
Definition: required_fields.c:177
UPB_PRINTF
#define UPB_PRINTF(str, first_vararg)
Definition: php-upb.c:122
map
zval * map
Definition: php/ext/google/protobuf/encode_decode.c:480
kUpb_CType_Int64
@ kUpb_CType_Int64
Definition: upb/upb/upb.h:294
upb_MessageValue::array_val
const upb_Array * array_val
Definition: upb/upb/reflection.h:50
upb_MessageValue::bool_val
bool bool_val
Definition: upb/upb/reflection.h:41
upb_FindContext_Push
static void upb_FindContext_Push(upb_FindContext *ctx, upb_FieldPathEntry ent)
Definition: required_fields.c:191
upb_MessageValue
Definition: upb/upb/reflection.h:40
upb_FieldDef_Label
upb_Label upb_FieldDef_Label(const upb_FieldDef *f)
Definition: upb/upb/def.c:539
upb_PrintfAppender::overflow
size_t overflow
Definition: required_fields.c:48
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
UPB_PTRADD
#define UPB_PTRADD(ptr, ofs)
Definition: php-upb.c:168
autogen_x86imm.f
f
Definition: autogen_x86imm.py:9
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
kUpb_Message_Begin
#define kUpb_Message_Begin
Definition: upb/upb/reflection.h:113
upb_FieldDef_IsMap
bool upb_FieldDef_IsMap(const upb_FieldDef *f)
Definition: upb/upb/def.c:659
upb_MapIterator_Next
bool upb_MapIterator_Next(const upb_Map *map, size_t *iter)
Definition: reflection.c:448
upb_StringView::size
size_t size
Definition: upb/upb/upb.h:74
upb_Array
Definition: msg_internal.h:424
upb_PrintfAppender::ptr
char * ptr
Definition: required_fields.c:46
upb_PrintfAppender
Definition: required_fields.c:44
upb_MessageValue::uint64_val
uint64_t uint64_val
Definition: upb/upb/reflection.h:47
reflection.h
upb_FieldPathVector_Init
static void upb_FieldPathVector_Init(upb_FieldPathVector *vec)
Definition: required_fields.c:171
upb_Message_Next
bool upb_Message_Next(const upb_Message *msg, const upb_MessageDef *m, const upb_DefPool *ext_pool, const upb_FieldDef **out_f, upb_MessageValue *out_val, size_t *iter)
Definition: reflection.c:245
upb_util_HasUnsetRequired
bool upb_util_HasUnsetRequired(const upb_Message *msg, const upb_MessageDef *m, const upb_DefPool *ext_pool, upb_FieldPathEntry **fields)
Definition: required_fields.c:293
upb_util_FindUnsetRequiredInternal
static void upb_util_FindUnsetRequiredInternal(upb_FindContext *ctx, const upb_Message *msg, const upb_MessageDef *m)
Definition: required_fields.c:233
upb_MessageValue::msg_val
const upb_Message * msg_val
Definition: upb/upb/reflection.h:49
upb_FindContext::has_unset_required
bool has_unset_required
Definition: required_fields.c:167
upb_FieldDef_CType
upb_CType upb_FieldDef_CType(const upb_FieldDef *f)
Definition: upb/upb/def.c:500
kUpb_Label_Required
@ kUpb_Label_Required
Definition: upb/upb/upb.h:303
d
static const fe d
Definition: curve25519_tables.h:19
upb_FieldPathVector
Definition: required_fields.c:156
upb_Message
void upb_Message
Definition: msg.h:49
upb_FieldDef_MessageSubDef
const upb_MessageDef * upb_FieldDef_MessageSubDef(const upb_FieldDef *f)
Definition: upb/upb/def.c:619
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
upb_FieldPathVector::path
upb_FieldPathEntry * path
Definition: required_fields.c:157
msg
std::string msg
Definition: client_interceptors_end2end_test.cc:372
upb_FieldDef
Definition: upb/upb/def.c:56
upb_MessageValue::map_val
const upb_Map * map_val
Definition: upb/upb/reflection.h:48
upb_Array_Size
size_t upb_Array_Size(const upb_Array *arr)
Definition: reflection.c:362
upb_Message_Has
bool upb_Message_Has(const upb_Message *msg, const upb_FieldDef *f)
Definition: reflection.c:112
upb_FindContext::stack
upb_FieldPathVector stack
Definition: required_fields.c:163
UPB_MAX
#define UPB_MAX(x, y)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:125
testing::internal::fmt
GTEST_API_ const char * fmt
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1808
upb_FieldPath_Printf
static void upb_FieldPath_Printf(upb_PrintfAppender *a, const char *fmt,...)
Definition: required_fields.c:52
key
const char * key
Definition: hpack_parser_table.cc:164
UPB_LIKELY
#define UPB_LIKELY(x)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:61
upb_FieldDef_IsRepeated
bool upb_FieldDef_IsRepeated(const upb_FieldDef *f)
Definition: upb/upb/def.c:651
upb_FieldPath_ToText
size_t upb_FieldPath_ToText(upb_FieldPathEntry **path, char *buf, size_t size)
Definition: required_fields.c:119
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
profile_analyzer.fields
list fields
Definition: profile_analyzer.py:266
first
StrT first
Definition: cxa_demangle.cpp:4884
upb_PrintfAppender::end
char * end
Definition: required_fields.c:47
upb_FieldPath_PutMapKey
static void upb_FieldPath_PutMapKey(upb_PrintfAppender *a, upb_MessageValue map_key, const upb_FieldDef *key_f)
Definition: required_fields.c:83
upb_FieldPathVector::cap
size_t cap
Definition: required_fields.c:159
upb_util_FindUnsetInMessage
static void upb_util_FindUnsetInMessage(upb_FindContext *ctx, const upb_Message *msg, const upb_MessageDef *m)
Definition: required_fields.c:203
upb_FieldDef_IsSubMessage
bool upb_FieldDef_IsSubMessage(const upb_FieldDef *f)
Definition: upb/upb/def.c:642
kUpb_CType_Bool
@ kUpb_CType_Bool
Definition: upb/upb/upb.h:287
upb_Map
Definition: msg_internal.h:581
upb_PrintfAppender::buf
char * buf
Definition: required_fields.c:45
iter
Definition: test_winkernel.cpp:47
upb_FieldDef_Name
const char * upb_FieldDef_Name(const upb_FieldDef *f)
Definition: upb/upb/def.c:549
ch
char ch
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3621
upb_MessageDef_FieldCount
int upb_MessageDef_FieldCount(const upb_MessageDef *m)
Definition: upb/upb/def.c:794
kUpb_CType_UInt64
@ kUpb_CType_UInt64
Definition: upb/upb/upb.h:295
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
upb_MessageDef_Field
const upb_FieldDef * upb_MessageDef_Field(const upb_MessageDef *m, int i)
Definition: upb/upb/def.c:828
regress.m
m
Definition: regress/regress.py:25
upb_MapIterator_Value
upb_MessageValue upb_MapIterator_Value(const upb_Map *map, size_t iter)
Definition: reflection.c:470
upb_FindContext::save_paths
bool save_paths
Definition: required_fields.c:168
upb_DefPool
Definition: upb/upb/def.c:217
upb_FieldPath_NullTerminate
static size_t upb_FieldPath_NullTerminate(upb_PrintfAppender *d, size_t size)
Definition: required_fields.c:72
required_fields.h
upb_FieldPathVector::size
size_t size
Definition: required_fields.c:158
UPB_LONGJMP
#define UPB_LONGJMP(buf, val)
Definition: php-upb.c:164
upb_FindContext::err
jmp_buf err
Definition: required_fields.c:166
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
upb_FindContext_Pop
static void upb_FindContext_Pop(upb_FindContext *ctx)
Definition: required_fields.c:197
upb_FindContext
Definition: required_fields.c:162


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:10