Exemplo n.º 1
0
Arquivo: handlers.c Projeto: YauzZ/upb
bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f,
                                 const upb_handlers *sub) {
  assert(sub);
  assert(!upb_handlers_isfrozen(h));
  assert(upb_fielddef_issubmsg(f));
  if (SUBH_F(h, f)) return false;  // Can't reset.
  if (UPB_UPCAST(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) {
    return false;
  }
  SUBH_F(h, f) = sub;
  upb_ref2(sub, h);
  return true;
}
Exemplo n.º 2
0
/* Output a symbolic value from the enum if found, else just print as int32. */
static bool textprinter_putenum(void *closure, const void *handler_data,
                                int32_t val) {
  upb_textprinter *p = closure;
  const upb_fielddef *f = handler_data;
  const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f));
  const char *label = upb_enumdef_iton(enum_def, val);
  if (label) {
    indent(p);
    putf(p, "%s: %s", upb_fielddef_name(f), label);
    endfield(p);
  } else {
    if (!textprinter_putint32(closure, handler_data, val))
      return false;
  }
  return true;
}
Exemplo n.º 3
0
// Allocates a new map_handlerdata_t given the map entry message definition. If
// the offset of the field within the parent message is also given, that is
// added to the handler data as well. Note that this is called *twice* per map
// field: once in the parent message handler setup when setting the startsubmsg
// handler and once in the map entry message handler setup when setting the
// key/value and endmsg handlers. The reason is that there is no easy way to
// pass the handlerdata down to the sub-message handler setup.
static map_handlerdata_t* new_map_handlerdata(
    size_t ofs,
    const upb_msgdef* mapentry_def,
    Descriptor* desc) {
    const upb_fielddef* key_field;
    const upb_fielddef* value_field;
    map_handlerdata_t* hd = ALLOC(map_handlerdata_t);
    hd->ofs = ofs;
    key_field = upb_msgdef_itof(mapentry_def, MAP_KEY_FIELD);
    assert(key_field != NULL);
    hd->key_field_type = upb_fielddef_type(key_field);
    value_field = upb_msgdef_itof(mapentry_def, MAP_VALUE_FIELD);
    assert(value_field != NULL);
    hd->value_field_type = upb_fielddef_type(value_field);
    hd->value_field_subdef = upb_fielddef_subdef(value_field);

    return hd;
}
Exemplo n.º 4
0
Arquivo: def.c Projeto: 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;
}
Exemplo n.º 5
0
static void check_repeated_field_type(VALUE val, const upb_fielddef* field) {
    assert(upb_fielddef_label(field) == UPB_LABEL_REPEATED);

    if (!RB_TYPE_P(val, T_DATA) || !RTYPEDDATA_P(val) ||
            RTYPEDDATA_TYPE(val) != &RepeatedField_type) {
        rb_raise(rb_eTypeError, "Expected repeated field array");
    }

    RepeatedField* self = ruby_to_RepeatedField(val);
    if (self->field_type != upb_fielddef_type(field)) {
        rb_raise(rb_eTypeError, "Repeated field array has wrong element type");
    }

    if (self->field_type == UPB_TYPE_MESSAGE ||
            self->field_type == UPB_TYPE_ENUM) {
        if (self->field_type_class !=
                get_def_obj(upb_fielddef_subdef(field))) {
            rb_raise(rb_eTypeError,
                     "Repeated field array has wrong message/enum class");
        }
    }
}
Exemplo n.º 6
0
Arquivo: def.c Projeto: 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;
}
Exemplo n.º 7
0
Arquivo: test_def.c Projeto: atdt/upb
static void test_cycles() {
  bool ok;
  upb_symtab *s = load_test_proto(&s);
  const upb_msgdef *m;
  const upb_fielddef *f;
  const upb_def *def;
  const upb_def *def2;

  /* Test cycle detection by making a cyclic def's main refcount go to zero
   * and then be incremented to one again. */
  def = upb_symtab_lookup(s, "A");
  upb_def_ref(def, &def);
  ASSERT(def);
  ASSERT(upb_def_isfrozen(def));
  upb_symtab_unref(s, &s);

  /* Message A has only one subfield: "optional B b = 1". */
  m = upb_downcast_msgdef(def);
  f = upb_msgdef_itof(m, 1);
  ASSERT(f);
  ASSERT(upb_fielddef_hassubdef(f));
  ASSERT(upb_msgdef_ntofz(m, "b") == f);
  ASSERT(upb_msgdef_ntof(m, "b", 1) == f);
  def2 = upb_fielddef_subdef(f);
  ASSERT(upb_downcast_msgdef(def2));
  ok = strcmp(upb_def_fullname(def2), "B") == 0;
  ASSERT(ok);

  upb_def_ref(def2, &def2);
  upb_def_unref(def, &def);

  /* We know "def" is still alive because it's reachable from def2. */
  ok = strcmp(upb_def_fullname(def), "A") == 0;
  ASSERT(ok);
  upb_def_unref(def2, &def2);
}
Exemplo n.º 8
0
Arquivo: def.c Projeto: Phuehvk/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_seterrliteral(s, "fielddef must have name and number set");
    return false;
  }
  if (!f->type_is_set_) {
    upb_status_seterrliteral(s, "fielddef type was not initialized");
    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;
}
Exemplo n.º 9
0
Arquivo: def.c Projeto: Phuehvk/upb
upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) {
  return (upb_def*)upb_fielddef_subdef(f);
}
Exemplo n.º 10
0
Arquivo: def.c Projeto: YauzZ/upb
const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) {
  const upb_def *def = upb_fielddef_subdef(f);
  return def ? upb_dyncast_enumdef(def) : NULL;
}
Exemplo n.º 11
0
Arquivo: def.c Projeto: YauzZ/upb
const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) {
  const upb_def *def = upb_fielddef_subdef(f);
  return def ? upb_dyncast_msgdef(def) : NULL;
}
Exemplo n.º 12
0
Arquivo: symtab.c Projeto: 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;
}
Exemplo n.º 13
0
Arquivo: symtab.c Projeto: atdt/upb
/* Starts a depth-first traversal at "def", recursing into any subdefs
 * (ie. submessage types).  Adds duplicates of existing defs to addtab
 * wherever necessary, so that the resulting symtab will be consistent once
 * addtab is added.
 *
 * More specifically, if any def D is found in the DFS that:
 *
 *   1. can reach a def that is being replaced by something in addtab, AND
 *
 *   2. is not itself being replaced already (ie. this name doesn't already
 *      exist in addtab)
 *
 * ...then a duplicate (new copy) of D will be added to addtab.
 *
 * Returns true if this happened for any def reachable from "def."
 *
 * It is slightly tricky to do this correctly in the presence of cycles.  If we
 * detect that our DFS has hit a cycle, we might not yet know if any SCCs on
 * our stack can reach a def in addtab or not.  Once we figure this out, that
 * answer needs to apply to *all* defs in these SCCs, even if we visited them
 * already.  So a straight up one-pass cycle-detecting DFS won't work.
 *
 * To work around this problem, we traverse each SCC (which we already
 * computed, since these defs are frozen) as a single node.  We first compute
 * whether the SCC as a whole can reach any def in addtab, then we dup (or not)
 * the entire SCC.  This requires breaking the encapsulation of upb_refcounted,
 * since that is where we get the data about what SCC we are in. */
static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab,
                            const void *new_owner, upb_inttable *seen,
                            upb_status *s) {
  upb_value v;
  bool need_dup;
  const upb_def *base;
  const void* memoize_key;

  /* Memoize results of this function for efficiency (since we're traversing a
   * DAG this is not needed to limit the depth of the search).
   *
   * We memoize by SCC instead of by individual def. */
  memoize_key = def->base.group;

  if (upb_inttable_lookupptr(seen, memoize_key, &v))
    return upb_value_getbool(v);

  /* Visit submessages for all messages in the SCC. */
  need_dup = false;
  base = def;
  do {
    upb_value v;
    const upb_msgdef *m;

    assert(upb_def_isfrozen(def));
    if (def->type == UPB_DEF_FIELD) continue;
    if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) {
      need_dup = true;
    }

    /* For messages, continue the recursion by visiting all subdefs, but only
     * ones in different SCCs. */
    m = upb_dyncast_msgdef(def);
    if (m) {
      upb_msg_field_iter i;
      for(upb_msg_field_begin(&i, m);
          !upb_msg_field_done(&i);
          upb_msg_field_next(&i)) {
        upb_fielddef *f = upb_msg_iter_field(&i);
        const upb_def *subdef;

        if (!upb_fielddef_hassubdef(f)) continue;
        subdef = upb_fielddef_subdef(f);

        /* Skip subdefs in this SCC. */
        if (def->base.group == subdef->base.group) continue;

        /* |= to avoid short-circuit; we need its side-effects. */
        need_dup |= upb_resolve_dfs(subdef, addtab, new_owner, seen, s);
        if (!upb_ok(s)) return false;
      }
    }
  } while ((def = (upb_def*)def->base.next) != base);

  if (need_dup) {
    /* Dup all defs in this SCC that don't already have entries in addtab. */
    def = base;
    do {
      const char *name;

      if (def->type == UPB_DEF_FIELD) continue;
      name = upb_def_fullname(def);
      if (!upb_strtable_lookup(addtab, name, NULL)) {
        upb_def *newdef = upb_def_dup(def, new_owner);
        if (!newdef) goto oom;
        newdef->came_from_user = false;
        if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef)))
          goto oom;
      }
    } while ((def = (upb_def*)def->base.next) != base);
  }

  upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup));
  return need_dup;

oom:
  upb_status_seterrmsg(s, "out of memory");
  return false;
}