static u64 pull_u64(struct file *f, off_t *poff) { le64 ret; pull_bytes(f, poff, &ret, sizeof(ret)); return le64_to_cpu(ret); }
static u32 pull_u32(struct file *f, off_t *poff) { le32 ret; pull_bytes(f, poff, &ret, sizeof(ret)); return le32_to_cpu(ret); }
static void read_output(struct space *space, struct file *f, off_t *poff, struct bitcoin_transaction_output *output) { output->amount = pull_u64(f, poff); output->script_length = pull_varint(f, poff); output->script = space_alloc(space, output->script_length); pull_bytes(f, poff, output->script, output->script_length); }
static void read_input(struct space *space, struct file *f, off_t *poff, struct bitcoin_transaction_input *input) { pull_hash(f, poff, input->hash); input->index = pull_u32(f, poff); input->script_length = pull_varint(f, poff); input->script = space_alloc(space, input->script_length); pull_bytes(f, poff, input->script, input->script_length); input->sequence_number = pull_u32(f, poff); }
bool pull_s16(const char **p, size_t *max_len, int16_t *val) { leint16_t v; if (pull_bytes(p, max_len, &v, sizeof(v))) { if (val) *val = le16_to_cpu(v); return true; } return false; }
static bool pull_foo(const char **p, size_t *len, struct foo *foo) { int ret; ret = pull_u64(p, len, &foo->vu64) + pull_u32(p, len, &foo->vu32) + pull_u16(p, len, &foo->vu16) + pull_u8(p, len, &foo->vu8) + pull_uchar(p, len, &foo->vuchar) + pull_s64(p, len, &foo->vs64) + pull_s32(p, len, &foo->vs32) + pull_s16(p, len, &foo->vs16) + pull_s8(p, len, &foo->vs8) + pull_char(p, len, &foo->vchar) + pull_bytes(p, len, foo->bytes, sizeof(foo->bytes)); if (ret != 11) ok1(len == 0 && *p == NULL); return ret == 11; }
int main(void) { char *buffer; const char *p; size_t len, left; struct foo *foo, *foo2; /* This is how many tests you plan to run */ plan_tests(17); /* Valgrind will make sure we don't read padding! */ foo = malloc(sizeof(*foo)); foo->vu64 = 0x01020304050607ULL; foo->vu32 = 0x08090a0b; foo->vu16 = 0x0c0d; foo->vu8 = 0x0e; foo->vuchar = 0x0f; foo->vs64 = -0x1011121314151617LL; foo->vs32 = -0x18191a1b; foo->vs16 = -0x1c1d; foo->vs8 = -0x1e; foo->vchar = -0x1f; memset(foo->bytes, 0x20, sizeof(foo->bytes)); strcpy(foo->bytes, "This is a test"); buffer = malloc(1); len = 0; ok1(push_foo(&buffer, &len, foo)); ok1(len <= sizeof(*foo)); /* Triggers valgrind's uninitialized value warning */ ok1(!memchr(buffer, 0x21, len)); p = buffer; left = len; foo2 = malloc(sizeof(*foo2)); ok1(pull_foo(&p, &left, foo2)); ok1(left == 0); ok1(p == buffer + len); ok1(foo_equal(foo, foo2)); /* Too-small for pull, it should fail and set ptr/len to 0 */ p = buffer; left = 0; ok1(!pull_u64(&p, &left, &foo2->vu64)); ok1(p == NULL && left == 0); /* Shouldn't change field! */ ok1(foo_equal(foo, foo2)); left = 7; ok1(!pull_u64(&p, &left, &foo2->vu64)); ok1(p == NULL && left == 0); /* Shouldn't change field! */ ok1(foo_equal(foo, foo2)); /* Discard should work. */ left = len; ok1(pull_bytes(&p, &left, NULL, sizeof(foo->bytes))); ok1(left == len - sizeof(foo->bytes)); /* Push failures should be clean. */ push_set_realloc(fail_reallocfn); p = buffer; left = len; ok1(!push_u64(&buffer, &left, foo->vu64)); ok1(p == buffer && left == len); free(buffer); free(foo); free(foo2); /* This exits depending on whether all tests passed */ return exit_status(); }
static void pull_hash(struct file *f, off_t *poff, u8 dst[32]) { pull_bytes(f, poff, dst, 32); }
bool pull_s8(const char **p, size_t *max_len, int8_t *val) { return pull_bytes(p, max_len, val, sizeof(*val)); }
bool pull_char(const char **p, size_t *max_len, char *val) { return pull_bytes(p, max_len, val, sizeof(*val)); }