Example #1
0
File: def.c Project: Phuehvk/upb
static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) {
  bool start = true;
  for (size_t i = 0; i < len; i++) {
    char c = str[i];
    if (c == '.') {
      if (start || !full) {
        upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str);
        return false;
      }
      start = true;
    } else if (start) {
      if (!upb_isletter(c)) {
        upb_status_seterrf(
            s, "invalid name: path components must start with a letter (%s)",
            str);
        return false;
      }
      start = false;
    } else {
      if (!upb_isalphanum(c)) {
        upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)",
                           str);
        return false;
      }
    }
  }
  return !start;
}
Example #2
0
static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
    upb_status_seterrliteral(s, "fielddef must have name and number set");
    return false;
  }
  if (upb_fielddef_hassubdef(f)) {
    if (f->subdef_is_symbolic) {
      upb_status_seterrf(s,
          "field '%s' has not been resolved", upb_fielddef_name(f));
      return false;
    }

    const upb_def *subdef = upb_fielddef_subdef(f);
    if (subdef == NULL) {
      upb_status_seterrf(s,
          "field %s.%s is missing required subdef",
          msgdef_name(f->msgdef), upb_fielddef_name(f));
      return false;
    } else if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
      upb_status_seterrf(s,
          "subdef of field %s.%s is not frozen or being frozen",
          msgdef_name(f->msgdef), upb_fielddef_name(f));
      return false;
    } else if (upb_fielddef_default_is_symbolic(f)) {
      upb_status_seterrf(s,
          "enum field %s.%s has not been resolved",
          msgdef_name(f->msgdef), upb_fielddef_name(f));
      return false;
    }
  }
  return true;
}
Example #3
0
static bool upb_fielddef_resolve(upb_fielddef *f, upb_def *def, upb_status *s) {
  assert(upb_dyncast_unresolveddef(f->def));
  upb_def_unref(f->def);
  f->def = def;
  if (f->type == UPB_TYPE(ENUM) && f->default_is_symbolic) {
    // Resolve the enum's default from a string to an integer.
    upb_byteregion *bytes = upb_value_getbyteregion(f->defaultval);
    assert(bytes);  // Points to either a real default or the empty string.
    upb_enumdef *e = upb_downcast_enumdef(f->def);
    int32_t val = 0;
    // Could do a sanity check that the default value does not have embedded
    // NULLs.
    if (upb_byteregion_len(bytes) == 0) {
      upb_value_setint32(&f->defaultval, e->defaultval);
    } else {
      size_t len;
      // ptr is guaranteed to be NULL-terminated because the byteregion was
      // created with upb_byteregion_newl().
      const char *ptr = upb_byteregion_getptr(bytes, 0, &len);
      assert(len == upb_byteregion_len(bytes));  // Should all be in one chunk.
      bool success = upb_enumdef_ntoi(e, ptr, &val);
      if (!success) {
        upb_status_seterrf(
            s, "Default enum value (%s) is not a member of the enum", ptr);
        return false;
      }
      upb_value_setint32(&f->defaultval, val);
    }
    upb_byteregion_free(bytes);
  }
  return true;
}
Example #4
0
static bool upb_fielddef_resolve(upb_fielddef *f, upb_def *def, upb_status *s) {
  assert(upb_dyncast_unresolveddef(f->def));
  upb_def_unref(f->def);
  f->def = def;
  if (f->type == UPB_TYPE(ENUM) && f->default_is_symbolic) {
    // Resolve the enum's default from a string to an integer.
    upb_strref *str = (upb_strref*)upb_value_getstrref(f->defaultval);
    assert(str);  // Should point to either a real default or the empty string.
    upb_enumdef *e = upb_downcast_enumdef(f->def);
    int32_t val = 0;
    // Could do a sanity check that the default value does not have embedded
    // NULLs.
    if (str->ptr[0] == '\0') {
      upb_value_setint32(&f->defaultval, e->defaultval);
    } else {
      bool success = upb_enumdef_ntoi(e, str->ptr, &val);
      if (!success) {
        upb_status_seterrf(
            s, "Default enum value (%s) is not a member of the enum", str);
        return false;
      }
      upb_value_setint32(&f->defaultval, val);
    }
    upb_strref_free(str);
  }
  return true;
}
Example #5
0
uint32_t upb_stdio_vprintf(upb_bytesink *sink, upb_status *status,
                           const char *fmt, va_list args) {
  upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, sink));
  int written = vfprintf(stdio->file, fmt, args);
  if (written < 0) {
    upb_status_seterrf(status, "Error writing to stdio stream.");
    return -1;
  }
  return written;
}
Example #6
0
File: handlers.c Project: YauzZ/upb
static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f,
                         upb_handlertype_t type) {
  upb_selector_t sel;
  assert(!upb_handlers_isfrozen(h));
  if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) {
    upb_status_seterrf(
        &h->status_, "type mismatch: field %s does not belong to message %s",
        upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h)));
    return -1;
  }
  if (!upb_handlers_getselector(f, type, &sel)) {
    upb_status_seterrf(
        &h->status_,
        "type mismatch: cannot register handler type %d for field %s",
        type, upb_fielddef_name(f));
    return -1;
  }
  return sel;
}
Example #7
0
File: def.c Project: YauzZ/upb
static bool upb_validate_field(upb_fielddef *f, upb_status *s) {
  if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) {
    upb_status_seterrmsg(s, "fielddef must have name and number set");
    return false;
  }
  if (!f->type_is_set_) {
    upb_status_seterrmsg(s, "fielddef type was not initialized");
    return false;
  }
  if (upb_fielddef_lazy(f) &&
      upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) {
    upb_status_seterrmsg(s,
                         "only length-delimited submessage fields may be lazy");
    return false;
  }
  if (upb_fielddef_hassubdef(f)) {
    if (f->subdef_is_symbolic) {
      upb_status_seterrf(s,
          "field '%s' has not been resolved", upb_fielddef_name(f));
      return false;
    }

    const upb_def *subdef = upb_fielddef_subdef(f);
    if (subdef == NULL) {
      upb_status_seterrf(s,
          "field %s.%s is missing required subdef",
          msgdef_name(f->msg.def), upb_fielddef_name(f));
      return false;
    } else if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) {
      upb_status_seterrf(s,
          "subdef of field %s.%s is not frozen or being frozen",
          msgdef_name(f->msg.def), upb_fielddef_name(f));
      return false;
    } else if (upb_fielddef_default_is_symbolic(f)) {
      upb_status_seterrf(s,
          "enum field %s.%s has not been resolved",
          msgdef_name(f->msg.def), upb_fielddef_name(f));
      return false;
    }
  }
  return true;
}
Example #8
0
File: def.c Project: Phuehvk/upb
bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) {
  if (f->msgdef) {
    upb_status_seterrliteral(
        s, "cannot change field number after adding to a message");
    return false;
  }
  if (number == 0 || number > UPB_MAX_FIELDNUMBER) {
    upb_status_seterrf(s, "invalid field number (%u)", number);
    return false;
  }
  f->number_ = number;
  return true;
}
Example #9
0
bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num,
                        upb_status *status) {
  if (!upb_isident(name, strlen(name), false)) {
    upb_status_seterrf(status, "name '%s' is not a valid identifier", name);
    return false;
  }
  if (upb_enumdef_ntoi(e, name, NULL)) {
    upb_status_seterrf(status, "name '%s' is already defined", name);
    return false;
  }
  if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) {
    upb_status_seterrliteral(status, "out of memory");
    return false;
  }
  if (!upb_inttable_lookup(&e->iton, num) &&
      !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) {
    upb_status_seterrliteral(status, "out of memory");
    upb_strtable_remove(&e->ntoi, name, NULL);
    return false;
  }
  return true;
}
Example #10
0
const char *upb_status_getstr(const upb_status *_status) {
  // Function is logically const but can modify internal state to materialize
  // the string.
  upb_status *status = (upb_status*)_status;
  if (status->str == NULL && status->space) {
    if (status->space->code_to_string) {
      status->space->code_to_string(status->code, status->buf, status->bufsize);
      status->str = status->buf;
    } else {
      upb_status_seterrf(status, "No message, error space=%s, code=%d\n",
                         status->space->name, status->code);
    }
  }
  return status->str;
}
Example #11
0
File: handlers.c Project: YauzZ/upb
// Checks whether the START* handler specified by f & type is missing even
// though it is required to convert the established type of an outer frame
// ("closure_type") into the established type of an inner frame (represented in
// the return closure type of this handler's attr.
bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type,
                upb_status *status) {
  upb_selector_t sel = getsel(h, f, type);
  if (h->table[sel].func) return true;
  const void *closure_type = effective_closure_type(h, f, type);
  const upb_handlerattr *attr = &h->table[sel].attr;
  const void *return_closure_type = upb_handlerattr_returnclosuretype(attr);
  if (closure_type && return_closure_type &&
      closure_type != return_closure_type) {
    upb_status_seterrf(status,
                       "expected start handler to return sub type for field %f",
                       upb_fielddef_name(f));
    return false;
  }
  return true;
}
Example #12
0
File: def.c Project: Phuehvk/upb
bool upb_fielddef_resolveenumdefault(upb_fielddef *f, upb_status *s) {
  if (!upb_fielddef_default_is_symbolic(f)) return true;

  str_t *str = upb_value_getptr(f->defaultval);
  const upb_enumdef *e = upb_downcast_enumdef(upb_fielddef_subdef(f));
  assert(str);  // Points to either a real default or the empty string.
  assert(e);
  if (str->len == 0) {
    // The "default default" for an enum is the first defined value.
    upb_value_setint32(&f->defaultval, e->defaultval);
  } else {
    int32_t val = 0;
    if (!upb_enumdef_ntoi(e, str->str, &val)) {
      upb_status_seterrf(s, "enum default not found in enum (%s)", str->str);
      return false;
    }
    upb_value_setint32(&f->defaultval, val);
  }
  f->default_is_string = false;
  freestr(str);
  return true;
}
Example #13
0
File: handlers.c Project: YauzZ/upb
bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) {
  // TODO: verify we have a transitive closure.
  for (int i = 0; i < n; i++) {
    upb_handlers *h = handlers[i];

    if (!upb_ok(&h->status_)) {
      upb_status_seterrf(s, "handlers for message %s had error status: %s",
                         upb_msgdef_fullname(upb_handlers_msgdef(h)),
                         upb_status_errmsg(&h->status_));
      return false;
    }

    // Check that there are no closure mismatches due to missing Start* handlers
    // or subhandlers with different type-level types.
    upb_msg_iter j;
    for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) {

      const upb_fielddef *f = upb_msg_iter_field(&j);
      if (upb_fielddef_isseq(f)) {
        if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s))
          return false;
      }

      if (upb_fielddef_isstring(f)) {
        if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s))
          return false;
      }

      if (upb_fielddef_issubmsg(f)) {
        bool hashandler = false;
        if (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSUBMSG)) ||
            upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSUBMSG))) {
          hashandler = true;
        }

        if (upb_fielddef_isseq(f) &&
            (upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_STARTSEQ)) ||
             upb_handlers_gethandler(h, getsel(h, f, UPB_HANDLER_ENDSEQ)))) {
          hashandler = true;
        }

        if (hashandler && !upb_handlers_getsubhandlers(h, f)) {
          // For now we add an empty subhandlers in this case.  It makes the
          // decoder code generator simpler, because it only has to handle two
          // cases (submessage has handlers or not) as opposed to three
          // (submessage has handlers in enclosing message but no subhandlers).
          //
          // This makes parsing less efficient in the case that we want to
          // notice a submessage but skip its contents (like if we're testing
          // for submessage presence or counting the number of repeated
          // submessages).  In this case we will end up parsing the submessage
          // field by field and throwing away the results for each, instead of
          // skipping the whole delimited thing at once.  If this is an issue we
          // can revisit it, but do remember that this only arises when you have
          // handlers (startseq/startsubmsg/endsubmsg/endseq) set for the
          // submessage but no subhandlers.  The uses cases for this are
          // limited.
          upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub);
          upb_handlers_setsubhandlers(h, f, sub);
          upb_handlers_unref(sub, &sub);
        }

        // TODO(haberman): check type of submessage.
        // This is slightly tricky; also consider whether we should check that
        // they match at setsubhandlers time.
      }
    }
  }

  if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s,
                             UPB_MAX_HANDLER_DEPTH)) {
    return false;
  }

  return true;
}
Example #14
0
bool upb_symtab_add(upb_symtab *s, upb_def **defs, int n, upb_status *status) {
  upb_rwlock_wrlock(&s->lock);

  // Add all defs to a table for resolution.
  upb_strtable addtab;
  upb_strtable_init(&addtab, n, sizeof(upb_symtab_ent));
  for (int i = 0; i < n; i++) {
    upb_def *def = defs[i];
    if (upb_strtable_lookup(&addtab, def->fqname)) {
      upb_status_seterrf(status, "Conflicting defs named '%s'", def->fqname);
      upb_strtable_free(&addtab);
      return false;
    }
    upb_strtable_insert(&addtab, def->fqname, &def);
  }

  // All existing defs that can reach defs that are being replaced must
  // themselves be replaced with versions that will point to the new defs.
  // Do a DFS -- any path that finds a new def must replace all ancestors.
  upb_strtable *symtab = &s->symtab;
  upb_strtable_iter i;
  upb_strtable_begin(&i, symtab);
  for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
    upb_def *open_defs[UPB_MAX_TYPE_DEPTH];
    const upb_symtab_ent *e = upb_strtable_iter_value(&i);
    upb_symtab_dfs(e->def, open_defs, 0, &addtab);
  }

  // Resolve all refs.
  upb_strtable_begin(&i, &addtab);
  for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
    const upb_symtab_ent *e = upb_strtable_iter_value(&i);
    upb_msgdef *m = upb_dyncast_msgdef(e->def);
    if(!m) continue;
    // Type names are resolved relative to the message in which they appear.
    const char *base = m->base.fqname;

    upb_msg_iter j;
    for(j = upb_msg_begin(m); !upb_msg_done(j); j = upb_msg_next(m, j)) {
      upb_fielddef *f = upb_msg_iter_field(j);
      if (f->type == 0) {
        upb_status_seterrf(status, "Field type was not set.");
        return false;
      }

      if (!upb_hassubdef(f)) continue;  // No resolving necessary.
      upb_downcast_unresolveddef(f->def);  // Type check.
      const char *name = f->def->fqname;

      // Resolve from either the addtab (pending adds) or symtab (existing
      // defs).  If both exist, prefer the pending add, because it will be
      // overwriting the existing def.
      upb_symtab_ent *found;
      if(!(found = upb_resolve(&addtab, base, name)) &&
         !(found = upb_resolve(symtab, base, name))) {
        upb_status_seterrf(status, "could not resolve symbol '%s' "
                                   "in context '%s'", name, base);
        return false;
      }

      // Check the type of the found def.
      upb_fieldtype_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM;
      if(found->def->type != expected) {
        upb_status_seterrliteral(status, "Unexpected type");
        return false;
      }
      if (!upb_fielddef_resolve(f, found->def, status)) return false;
    }
  }

  // The defs in the transaction have been vetted, and can be moved to the
  // symtab without causing errors.
  upb_strtable_begin(&i, &addtab);
  for(; !upb_strtable_done(&i); upb_strtable_next(&i)) {
    const upb_symtab_ent *tmptab_e = upb_strtable_iter_value(&i);
    upb_def_movetosymtab(tmptab_e->def, s);
    upb_symtab_ent *symtab_e =
        upb_strtable_lookup(&s->symtab, tmptab_e->def->fqname);
    if(symtab_e) {
      upb_deflist_push(&s->olddefs, symtab_e->def);
      symtab_e->def = tmptab_e->def;
    } else {
      upb_strtable_insert(&s->symtab, tmptab_e->def->fqname, tmptab_e);
    }
  }

  upb_strtable_free(&addtab);
  upb_rwlock_unlock(&s->lock);
  upb_symtab_gc(s);
  return true;
}
Example #15
0
File: symtab.c Project: atdt/upb
/* TODO(haberman): we need a lot more testing of error conditions.
 * The came_from_user stuff in particular is not tested. */
bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor,
                    upb_status *status) {
  int i;
  upb_strtable_iter iter;
  upb_def **add_defs = NULL;
  upb_strtable addtab;
  upb_inttable seen;

  assert(!upb_symtab_isfrozen(s));
  if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) {
    upb_status_seterrmsg(status, "out of memory");
    return false;
  }

  /* Add new defs to our "add" set. */
  for (i = 0; i < n; i++) {
    upb_def *def = defs[i];
    const char *fullname;
    upb_fielddef *f;

    if (upb_def_isfrozen(def)) {
      upb_status_seterrmsg(status, "added defs must be mutable");
      goto err;
    }
    assert(!upb_def_isfrozen(def));
    fullname = upb_def_fullname(def);
    if (!fullname) {
      upb_status_seterrmsg(
          status, "Anonymous defs cannot be added to a symtab");
      goto err;
    }

    f = upb_dyncast_fielddef_mutable(def);

    if (f) {
      if (!upb_fielddef_containingtypename(f)) {
        upb_status_seterrmsg(status,
                             "Standalone fielddefs must have a containing type "
                             "(extendee) name set");
        goto err;
      }
    } else {
      if (upb_strtable_lookup(&addtab, fullname, NULL)) {
        upb_status_seterrf(status, "Conflicting defs named '%s'", fullname);
        goto err;
      }
      /* We need this to back out properly, because if there is a failure we
       * need to donate the ref back to the caller. */
      def->came_from_user = true;
      upb_def_donateref(def, ref_donor, s);
      if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def)))
        goto oom_err;
    }
  }

  /* Add standalone fielddefs (ie. extensions) to the appropriate messages.
   * If the appropriate message only exists in the existing symtab, duplicate
   * it so we have a mutable copy we can add the fields to. */
  for (i = 0; i < n; i++) {
    upb_def *def = defs[i];
    upb_fielddef *f = upb_dyncast_fielddef_mutable(def);
    const char *msgname;
    upb_value v;
    upb_msgdef *m;

    if (!f) continue;
    msgname = upb_fielddef_containingtypename(f);
    /* We validated this earlier in this function. */
    assert(msgname);

    /* If the extendee name is absolutely qualified, move past the initial ".".
     * TODO(haberman): it is not obvious what it would mean if this was not
     * absolutely qualified. */
    if (msgname[0] == '.') {
      msgname++;
    }

    if (upb_strtable_lookup(&addtab, msgname, &v)) {
      /* Extendee is in the set of defs the user asked us to add. */
      m = upb_value_getptr(v);
    } else {
      /* Need to find and dup the extendee from the existing symtab. */
      const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname);
      if (!frozen_m) {
        upb_status_seterrf(status,
                           "Tried to extend message %s that does not exist "
                           "in this SymbolTable.",
                           msgname);
        goto err;
      }
      m = upb_msgdef_dup(frozen_m, s);
      if (!m) goto oom_err;
      if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) {
        upb_msgdef_unref(m, s);
        goto oom_err;
      }
    }

    if (!upb_msgdef_addfield(m, f, ref_donor, status)) {
      goto err;
    }
  }

  /* Add dups of any existing def that can reach a def with the same name as
   * anything in our "add" set. */
  if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err;
  upb_strtable_begin(&iter, &s->symtab);
  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
    upb_resolve_dfs(def, &addtab, s, &seen, status);
    if (!upb_ok(status)) goto err;
  }
  upb_inttable_uninit(&seen);

  /* Now using the table, resolve symbolic references for subdefs. */
  upb_strtable_begin(&iter, &addtab);
  for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
    const char *base;
    upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
    upb_msgdef *m = upb_dyncast_msgdef_mutable(def);
    upb_msg_field_iter j;

    if (!m) continue;
    /* Type names are resolved relative to the message in which they appear. */
    base = upb_msgdef_fullname(m);

    for(upb_msg_field_begin(&j, m);
        !upb_msg_field_done(&j);
        upb_msg_field_next(&j)) {
      upb_fielddef *f = upb_msg_iter_field(&j);
      const char *name = upb_fielddef_subdefname(f);
      if (name && !upb_fielddef_subdef(f)) {
        /* Try the lookup in the current set of to-be-added defs first. If not
         * there, try existing defs. */
        upb_def *subdef = upb_resolvename(&addtab, base, name);
        if (subdef == NULL) {
          subdef = upb_resolvename(&s->symtab, base, name);
        }
        if (subdef == NULL) {
          upb_status_seterrf(
              status, "couldn't resolve name '%s' in message '%s'", name, base);
          goto err;
        } else if (!upb_fielddef_setsubdef(f, subdef, status)) {
          goto err;
        }
      }
    }
  }

  /* We need an array of the defs in addtab, for passing to upb_def_freeze. */
  add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab));
  if (add_defs == NULL) goto oom_err;
  upb_strtable_begin(&iter, &addtab);
  for (n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
    add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&iter));
  }

  if (!upb_def_freeze(add_defs, n, status)) goto err;

  /* This must be delayed until all errors have been detected, since error
   * recovery code uses this table to cleanup defs. */
  upb_strtable_uninit(&addtab);

  /* TODO(haberman) we don't properly handle errors after this point (like
   * OOM in upb_strtable_insert() below). */
  for (i = 0; i < n; i++) {
    upb_def *def = add_defs[i];
    const char *name = upb_def_fullname(def);
    upb_value v;
    bool success;

    if (upb_strtable_remove(&s->symtab, name, &v)) {
      const upb_def *def = upb_value_getptr(v);
      upb_def_unref(def, s);
    }
    success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def));
    UPB_ASSERT_VAR(success, success == true);
  }
  free(add_defs);
  return true;

oom_err:
  upb_status_seterrmsg(status, "out of memory");
err: {
    /* For defs the user passed in, we need to donate the refs back.  For defs
     * we dup'd, we need to just unref them. */
    upb_strtable_begin(&iter, &addtab);
    for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) {
      upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter));
      bool came_from_user = def->came_from_user;
      def->came_from_user = false;
      if (came_from_user) {
        upb_def_donateref(def, s, ref_donor);
      } else {
        upb_def_unref(def, s);
      }
    }
  }
  upb_strtable_uninit(&addtab);
  free(add_defs);
  assert(!upb_ok(status));
  return false;
}