Пример #1
0
static void test_mapentry_check() {
  upb_status s = UPB_STATUS_INIT;
  upb_msgdef *m = upb_msgdef_new(&m);
  upb_fielddef *f = upb_fielddef_new(&f);
  upb_symtab *symtab = upb_symtab_new(&symtab);
  upb_msgdef *subm = upb_msgdef_new(&subm);
  upb_def *defs[2];

  upb_msgdef_setfullname(m, "TestMessage", &s);
  upb_fielddef_setname(f, "field1", &s);
  upb_fielddef_setnumber(f, 1, &s);
  upb_fielddef_setlabel(f, UPB_LABEL_OPTIONAL);
  upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
  upb_fielddef_setsubdefname(f, ".MapEntry", &s);
  upb_msgdef_addfield(m, f, &f, &s);
  ASSERT(upb_ok(&s));

  upb_msgdef_setfullname(subm, "MapEntry", &s);
  upb_msgdef_setmapentry(subm, true);

  defs[0] = upb_msgdef_upcast_mutable(m);
  defs[1] = upb_msgdef_upcast_mutable(subm);
  upb_symtab_add(symtab, defs, 2, NULL, &s);
  /* Should not have succeeded: non-repeated field pointing to a MapEntry. */
  ASSERT(!upb_ok(&s));

  upb_fielddef_setlabel(f, UPB_LABEL_REPEATED);
  upb_symtab_add(symtab, defs, 2, NULL, &s);
  ASSERT(upb_ok(&s));

  upb_symtab_unref(symtab, &symtab);
  upb_msgdef_unref(subm, &subm);
  upb_msgdef_unref(m, &m);
}
Пример #2
0
static void test_symbol_resolution() {
  upb_status s = UPB_STATUS_INIT;
  upb_def *defs[2];
  upb_msgdef *m1;
  upb_msgdef *m2;
  upb_msgdef *m3;
  upb_fielddef *m3_field1;
  upb_fielddef *m3_field2;

  upb_symtab *symtab = upb_symtab_new(&symtab);
  ASSERT(symtab);

  /* m1 has name "A.B.C" and no fields. We'll add it to the symtab now. */
  m1 = upb_msgdef_new(&m1);
  ASSERT(m1);
  ASSERT_STATUS(upb_msgdef_setfullname(m1, "A.B.C", &s), &s);
  ASSERT_STATUS(upb_symtab_add(symtab, (upb_def**)&m1, 1,
                               NULL, &s), &s);

  /* m2 has name "D.E" and no fields. We'll add it in the same batch as m3
   * below. */
  m2 = upb_msgdef_new(&m2);
  ASSERT(m2);
  ASSERT_STATUS(upb_msgdef_setfullname(m2, "D.E", &s), &s);

  /* m3 has name "F.G" and two fields, of type A.B.C and D.E respectively. We'll
   * add it in the same batch as m2 above. */
  m3 = upb_msgdef_new(&m3);
  ASSERT(m3);
  ASSERT_STATUS(upb_msgdef_setfullname(m3, "F.G", &s), &s);
  m3_field1 = upb_fielddef_new(&m3_field1);
  ASSERT_STATUS(upb_fielddef_setname(m3_field1, "field1", &s), &s);
  ASSERT_STATUS(upb_fielddef_setnumber(m3_field1, 1, &s), &s);
  upb_fielddef_setlabel(m3_field1, UPB_LABEL_OPTIONAL);
  upb_fielddef_settype(m3_field1, UPB_TYPE_MESSAGE);
  ASSERT_STATUS(upb_fielddef_setsubdefname(m3_field1, ".A.B.C", &s), &s);
  ASSERT_STATUS(upb_msgdef_addfield(m3, m3_field1, NULL, &s), &s);

  m3_field2 = upb_fielddef_new(&m3_field2);
  ASSERT_STATUS(upb_fielddef_setname(m3_field2, "field2", &s), &s);
  ASSERT_STATUS(upb_fielddef_setnumber(m3_field2, 2, &s), &s);
  upb_fielddef_setlabel(m3_field2, UPB_LABEL_OPTIONAL);
  upb_fielddef_settype(m3_field2, UPB_TYPE_MESSAGE);
  ASSERT_STATUS(upb_fielddef_setsubdefname(m3_field2, ".D.E", &s), &s);
  ASSERT_STATUS(upb_msgdef_addfield(m3, m3_field2, NULL, &s), &s);

  defs[0] = upb_msgdef_upcast_mutable(m2);
  defs[1] = upb_msgdef_upcast_mutable(m3);
  ASSERT_STATUS(upb_symtab_add(symtab, defs, 2, NULL, &s), &s);

  upb_fielddef_unref(m3_field2, &m3_field2);
  upb_fielddef_unref(m3_field1, &m3_field1);
  upb_msgdef_unref(m3, &m3);
  upb_msgdef_unref(m2, &m2);
  upb_msgdef_unref(m1, &m1);
  upb_symtab_unref(symtab, &symtab);
}
Пример #3
0
static void test_freeze_free() {
  bool ok;

  /* Test that freeze frees defs that were only being kept alive by virtue of
   * sharing a group with other defs that are being frozen. */
  upb_msgdef *m1 = upb_msgdef_newnamed("M1", &m1);
  upb_msgdef *m2 = upb_msgdef_newnamed("M2", &m2);
  upb_msgdef *m3 = upb_msgdef_newnamed("M3", &m3);
  upb_msgdef *m4 = upb_msgdef_newnamed("M4", &m4);
  upb_fielddef *f = upb_fielddef_new(&f);

  /* Freeze M4 and make M1 point to it. */
  upb_def_freeze((upb_def*const*)&m4, 1, NULL);

  upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
  ASSERT(upb_fielddef_setnumber(f, 1, NULL));
  ASSERT(upb_fielddef_setname(f, "foo", NULL));
  ASSERT(upb_fielddef_setmsgsubdef(f, m4, NULL));

  ASSERT(upb_msgdef_addfield(m1, f, &f, NULL));

  /* After this unref, M1 is the only thing keeping M4 alive. */
  upb_msgdef_unref(m4, &m4);

  /* Force M1/M2/M3 into a single mutable refcounting group. */
  f = upb_fielddef_new(&f);
  upb_fielddef_settype(f, UPB_TYPE_MESSAGE);
  ASSERT(upb_fielddef_setnumber(f, 1, NULL));
  ASSERT(upb_fielddef_setname(f, "foo", NULL));

  ASSERT(upb_fielddef_setmsgsubdef(f, m1, NULL));
  ASSERT(upb_fielddef_setmsgsubdef(f, m2, NULL));
  ASSERT(upb_fielddef_setmsgsubdef(f, m3, NULL));

  /* Make M3 cyclic with itself. */
  ASSERT(upb_msgdef_addfield(m3, f, &f, NULL));

  /* These will be kept alive since they are in the same refcounting group as
   * M3, which still has a ref.  Note: this behavior is not guaranteed by the
   * API, but true in practice with its current implementation. */
  upb_msgdef_unref(m1, &m1);
  upb_msgdef_unref(m2, &m2);

  /* Test that they are still alive (NOT allowed by the API). */
  ok = strcmp("M1", upb_msgdef_fullname(m1)) == 0;
  ASSERT(ok);
  ok = strcmp("M2", upb_msgdef_fullname(m2)) == 0;
  ASSERT(ok);

  /* Freeze M3.  If the test leaked no memory, then freeing m1 and m2 was
   * successful. */
  ASSERT(upb_def_freeze((upb_def*const*)&m3, 1, NULL));

  upb_msgdef_unref(m3, &m3);
}
Пример #4
0
static void test_descriptor_flags() {
  upb_msgdef *m = upb_msgdef_new(&m);
  upb_msgdef *m2;
  upb_status s = UPB_STATUS_INIT;

  ASSERT(upb_msgdef_mapentry(m) == false);
  upb_msgdef_setfullname(m, "TestMessage", &s);
  ASSERT(upb_ok(&s));
  upb_msgdef_setmapentry(m, true);
  ASSERT(upb_msgdef_mapentry(m) == true);
  m2 = upb_msgdef_dup(m, &m2);
  ASSERT(upb_msgdef_mapentry(m2) == true);
  upb_msgdef_unref(m, &m);
  upb_msgdef_unref(m2, &m2);
}
Пример #5
0
static void test_noreftracking() {
  /* Reftracking is not required; clients can pass UPB_UNTRACKED_REF for owner. */
  upb_msgdef *md = upb_msgdef_new(UPB_UNTRACKED_REF);
  upb_msgdef_ref(md, UPB_UNTRACKED_REF);

  /* Clients can mix tracked and untracked refs. */
  upb_msgdef_ref(md, &md);

  upb_msgdef_unref(md, UPB_UNTRACKED_REF);
  upb_msgdef_unref(md, UPB_UNTRACKED_REF);

  /* Call some random function on the messagedef to test that it is alive. */
  ASSERT(!upb_msgdef_isfrozen(md));

  upb_msgdef_unref(md, &md);
}
Пример #6
0
static void freehandlers(upb_refcounted *r) {
  upb_handlers *h = (upb_handlers*)r;
  for (int i = 0; i < h->msg->selector_count; i++) {
    upb_handlerfree *cleanup = h->table[i].attr.cleanup;
    if (cleanup) {
      cleanup(h->table[i].attr.handler_data_);
    }
  }
  upb_msgdef_unref(h->msg, h);
  free(h->sub);
  free(h);
}
Пример #7
0
void upb_fielddef_unref(upb_fielddef *f) {
  // TODO.
  (void)f;
  if (!f) return;
  if (upb_atomic_unref(&f->refcount)) {
    if (f->msgdef) {
      upb_msgdef_unref(f->msgdef);
      // fielddef might be deleted now.
    } else {
      upb_fielddef_free(f);
    }
  }
}
Пример #8
0
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
  upb_msgdef *newm = upb_msgdef_new(owner);
  if (!newm) return NULL;
  upb_def_setfullname(upb_upcast(newm), upb_def_fullname(upb_upcast(m)));
  upb_msg_iter i;
  for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
    upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
    if (!f || !upb_msgdef_addfield(newm, f, &f)) {
      upb_msgdef_unref(newm, owner);
      return NULL;
    }
  }
  return newm;
}
Пример #9
0
static void test_partial_freeze() {
  /* Test that freeze of only part of the graph correctly adjusts objects that
   * point to the newly-frozen objects. */
  upb_msgdef *m1 = upb_msgdef_newnamed("M1", &m1);
  upb_msgdef *m2 = upb_msgdef_newnamed("M2", &m2);
  upb_msgdef *m3 = upb_msgdef_newnamed("M3", &m3);
  upb_fielddef *f1 = upb_fielddef_new(&f1);
  upb_fielddef *f2 = upb_fielddef_new(&f2);
  upb_def *defs[2];
  defs[0] = upb_msgdef_upcast_mutable(m1);
  defs[1] = upb_msgdef_upcast_mutable(m2);

  upb_fielddef_settype(f1, UPB_TYPE_MESSAGE);
  ASSERT(upb_fielddef_setnumber(f1, 1, NULL));
  ASSERT(upb_fielddef_setname(f1, "f1", NULL));
  ASSERT(upb_fielddef_setmsgsubdef(f1, m1, NULL));

  upb_fielddef_settype(f2, UPB_TYPE_MESSAGE);
  ASSERT(upb_fielddef_setnumber(f2, 2, NULL));
  ASSERT(upb_fielddef_setname(f2, "f2", NULL));
  ASSERT(upb_fielddef_setmsgsubdef(f2, m2, NULL));

  ASSERT(upb_msgdef_addfield(m3, f1, &f1, NULL));
  ASSERT(upb_msgdef_addfield(m3, f2, &f2, NULL));

  /* Freeze M1 and M2, which should cause the group to be split
   * and m3 (left mutable) to take references on m1 and m2. */
  ASSERT(upb_def_freeze(defs, 2, NULL));

  ASSERT(upb_msgdef_isfrozen(m1));
  ASSERT(upb_msgdef_isfrozen(m2));
  ASSERT(!upb_msgdef_isfrozen(m3));

  upb_msgdef_unref(m1, &m1);
  upb_msgdef_unref(m2, &m2);
  upb_msgdef_unref(m3, &m3);
}
Пример #10
0
Файл: def.c Проект: YauzZ/upb
upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) {
  upb_msgdef *newm = upb_msgdef_new(owner);
  if (!newm) return NULL;
  bool ok = upb_def_setfullname(UPB_UPCAST(newm),
                                upb_def_fullname(UPB_UPCAST(m)), NULL);
  UPB_ASSERT_VAR(ok, ok);
  upb_msg_iter i;
  for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) {
    upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f);
    if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) {
      upb_msgdef_unref(newm, owner);
      return NULL;
    }
  }
  return newm;
}
Пример #11
0
void Descriptor_free(void* _self) {
  Descriptor* self = _self;
  upb_msgdef_unref(self->msgdef, &self->msgdef);
  if (self->layout) {
    free_layout(self->layout);
  }
  if (self->fill_handlers) {
    upb_handlers_unref(self->fill_handlers, &self->fill_handlers);
  }
  if (self->fill_method) {
    upb_pbdecodermethod_unref(self->fill_method, &self->fill_method);
  }
  if (self->pb_serialize_handlers) {
    upb_handlers_unref(self->pb_serialize_handlers,
                       &self->pb_serialize_handlers);
  }
  if (self->json_serialize_handlers) {
    upb_handlers_unref(self->pb_serialize_handlers,
                       &self->json_serialize_handlers);
  }
  xfree(self);
}
Пример #12
0
void free_layout(MessageLayout* layout) {
  xfree(layout->fields);
  upb_msgdef_unref(layout->msgdef, &layout->msgdef);
  xfree(layout);
}
Пример #13
0
Файл: symtab.c Проект: 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;
}