예제 #1
0
static int c_variant_write_one(CVariant *cv, char basic, const void *arg, size_t n_arg) {
        CVariantLevel *level;
        CVariantType info;
        void *front;
        int r;

        assert(n_arg > 0);

        level = cv->state->levels + cv->state->i_levels;
        if (_unlikely_(level->n_type < 1))
                return c_variant_poison(cv, -EBADRQC);

        r = c_variant_signature_next(level->type, level->n_type, &info);
        assert(r == 1);

        r = c_variant_append(cv, basic, &info, 0, n_arg, &front, 0, NULL);
        if (r < 0)
                return r;

        memcpy(front, arg, n_arg);
        return 0;
}
예제 #2
0
static int c_variant_insert_one(CVariant *cv, const char *type, const struct iovec *vecs, size_t n_vecs, size_t size) {
        CVariantLevel *level;
        CVariantType info;
        size_t n_type, i, idx;
        struct iovec *v;
        uint64_t frame;
        int r;

        level = cv->state->levels + cv->state->i_levels;
        if (_unlikely_(level->n_type < 1))
                return c_variant_poison(cv, -EBADRQC);

        r = c_variant_signature_next(level->type, level->n_type, &info);
        assert(r == 1);

        n_type = strlen(type);
        if (_unlikely_(n_type != info.n_type || strncmp(type, info.type, n_type)))
                return c_variant_poison(cv, -EBADRQC);

        if (_unlikely_(info.size > 0 && size != info.size))
                return c_variant_poison(cv, -EBADMSG);

        r = c_variant_append(cv, *type, &info, n_vecs + 1, 0, NULL, 0, NULL);
        if (r < 0)
                return r;

        /* make sure there are at least 'n_vecs + 1' unused vectors */
        assert(cv->n_vecs - level->v_front - level->v_tail - 2U >= n_vecs + 1U);

        /*
         * Clip the current front and prepare the next vector with the
         * remaining buffer space. Then insert the requested vectors in between
         * both and verify alignment restrictions.
         */
        v = cv->vecs + level->v_front;
        v[n_vecs + 1].iov_base = (char *)v->iov_base + level->i_front;
        v[n_vecs + 1].iov_len = v->iov_len - level->i_front;
        v->iov_len = level->i_front;

        for (i = 0; i < n_vecs; ++i) {
                idx = level->v_front + i + 1;
                if (((char *)(cv->vecs + cv->n_vecs))[idx]) {
                        ((char *)(cv->vecs + cv->n_vecs))[idx] = false;
                        free((cv->vecs + idx)->iov_base);
                }
                cv->vecs[idx] = vecs[i];
        }

        level->v_front += n_vecs + 1;
        level->i_front = 0;
        level->offset += size;

        /* see c_variant_end_one(); we have to update the framing offset */
        if (info.size < 1) {
                switch (level->enclosing) {
                case C_VARIANT_TUPLE_OPEN:
                case C_VARIANT_PAIR_OPEN:
                        /* last element never stores framing offsets */
                        if (level->n_type < 1)
                                break;
                        /* fallthrough */
                case C_VARIANT_ARRAY:
                        assert(level->i_tail >= 8);
                        assert(!(level->i_tail & 7));

                        v = cv->vecs + cv->n_vecs - level->v_tail - 1;
                        frame = level->offset;
                        memcpy((char *)v->iov_base + level->i_tail - 8, &frame, 8);
                        break;
                }
        }

        return 0;
}
예제 #3
0
static int c_variant_begin_one(CVariant *cv, char container, const char *variant) {
        CVariantLevel *next, *level;
        CVariantType info;
        size_t n_tail;
        void *tail;
        int r;

        r = c_variant_ensure_level(cv);
        if (r < 0)
                return r;

        if (container == C_VARIANT_VARIANT)
                n_tail = strlen(variant);
        else
                n_tail = 0;

        level = cv->state->levels + cv->state->i_levels;
        if (_unlikely_(level->n_type < 1))
                return c_variant_poison(cv, -EBADRQC);

        r = c_variant_signature_next(level->type, level->n_type, &info);
        assert(r == 1);

        r = c_variant_append(cv, container, &info, 0, 0, NULL, n_tail, &tail);
        if (r < 0)
                return r;

        c_variant_push_level(cv);
        next = cv->state->levels + cv->state->i_levels;

        next->size = info.size;
        next->i_tail = level->i_tail;
        next->v_tail = level->v_tail;
        /* wordsize is unused */
        next->enclosing = container;
        next->v_front = level->v_front;
        next->i_front = level->i_front;
        next->index = 0;
        next->offset = 0;

        switch (container) {
        case C_VARIANT_VARIANT:
                memcpy(tail, variant, n_tail);
                next->i_tail += n_tail;
                next->n_type = n_tail;
                next->index = n_tail;
                next->type = tail;
                break;
        case C_VARIANT_MAYBE:
        case C_VARIANT_ARRAY:
                next->n_type = info.n_type - 1;
                next->type = info.type + 1;
                break;
        case C_VARIANT_TUPLE_OPEN:
        case C_VARIANT_PAIR_OPEN:
                next->n_type = info.n_type - 2;
                next->type = info.type + 1;
                break;
        default:
                assert(0);
                break;
        }

        return 0;
}
예제 #4
0
static void test_signature_api(void) {
        CVariantType t;
        int r;

        /*
         * Verify that we never read more data from the signature than
         * requested by the caller. Hence, this call should never see the
         * invalid '$' element.
         */

        r = c_variant_signature_next("$foobar", 0, &t);
        assert(r == 0);
        assert(t.alignment == 0);
        assert(t.size == 0);
        assert(t.bound_size == 0);
        assert(t.n_levels == 0);
        assert(t.n_type == 0);

        /*
         * Verify that we never look ahead of a parsed type. That is, parsing
         * the valid element 'b' should return before looking at the invalid
         * element '$' ahead.
         * But if we then strip it (that is, we continue after the parsed
         * element), it should immediately fail but leave 't' untouched.
         */

        r = c_variant_signature_next("b$foobar", 8, &t);
        assert(r == 1);
        assert(t.alignment == 0);
        assert(t.size == 1);
        assert(t.bound_size == 0);
        assert(t.n_levels == 0);
        assert(t.n_type == 1);
        assert(!strncmp(t.type, "b", t.n_type));

        r = c_variant_signature_next(t.type + t.n_type, 8 - t.n_type, &t);
        assert(r < 0);
        assert(r == -EMEDIUMTYPE);
        /* @t must not have been touched! */
        assert(t.alignment == 0);
        assert(t.size == 1);
        assert(t.bound_size == 0);
        assert(t.n_levels == 0);
        assert(t.n_type == 1);
        assert(!strncmp(t.type, "b", t.n_type));

        /*
         * Make sure an inappropriately sized signature will result in an
         * immediate error without the data being looked at.
         * This is not explicitly part of the *ABI*, but reasonable enough to
         * test for.
         */

        r = c_variant_signature_next(NULL, SIZE_MAX, &t);
        assert(r < 0);
        assert(r == -EMSGSIZE);

        /*
         * Make sure API-types are rejected in type-strings. This includes
         * anything that is not a valid element.
         */

        r = c_variant_signature_next("r", 1, &t);
        assert(r < 0);
        assert(r == -EMEDIUMTYPE);

        r = c_variant_signature_next("e", 1, &t);
        assert(r < 0);
        assert(r == -EMEDIUMTYPE);

        r = c_variant_signature_next("?", 1, &t);
        assert(r < 0);
        assert(r == -EMEDIUMTYPE);

        r = c_variant_signature_next("*", 1, &t);
        assert(r < 0);
        assert(r == -EMEDIUMTYPE);
}