diff --git a/ccan/README b/ccan/README index 63b5a00e6..2c9d9a93b 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2446-g1b4ed377 +CCAN version: init-2451-gfedf5151 diff --git a/ccan/ccan/htable/_info b/ccan/ccan/htable/_info index a3bb76db6..ea11beb44 100644 --- a/ccan/ccan/htable/_info +++ b/ccan/ccan/htable/_info @@ -41,7 +41,7 @@ * } * * // Comparison function. - * static bool streq(const void *e, void *string) + * static bool nameeq(const void *e, void *string) * { * return strcmp(((struct name_to_digit *)e)->name, string) == 0; * } @@ -49,13 +49,13 @@ * // We let them add their own aliases, eg. --alias=v=5 * static void add_alias(struct htable *ht, const char *alias) * { - * char *eq; + * char *eq, *name; * struct name_to_digit *n; * * n = malloc(sizeof(*n)); - * n->name = strdup(alias); + * n->name = name = strdup(alias); * - * eq = strchr(n->name, '='); + * eq = strchr(name, '='); * if (!eq || ((n->val = atoi(eq+1)) == 0 && !strcmp(eq+1, "0"))) * errx(1, "Usage: --alias=="); * *eq = '\0'; @@ -89,7 +89,7 @@ * for (val = 0; i < argc; i++) { * struct name_to_digit *n; * n = htable_get(&ht, hash_string(argv[i]), - * streq, argv[i]); + * nameeq, argv[i]); * if (!n) * errx(1, "Invalid digit name %s", argv[i]); * // Append it to the value we are building up. @@ -110,6 +110,7 @@ int main(int argc, char *argv[]) if (strcmp(argv[1], "depends") == 0) { printf("ccan/compiler\n"); + printf("ccan/str\n"); return 0; } diff --git a/ccan/ccan/htable/htable.c b/ccan/ccan/htable/htable.c index e1d13699e..f3568230a 100644 --- a/ccan/ccan/htable/htable.c +++ b/ccan/ccan/htable/htable.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,7 @@ bool htable_init_sized(struct htable *ht, return false; } htable_adjust_capacity(ht); + (void)htable_debug(ht, HTABLE_LOC); return true; } @@ -88,7 +90,7 @@ void htable_clear(struct htable *ht) htable_init(ht, ht->rehash, ht->priv); } -bool htable_copy(struct htable *dst, const struct htable *src) +bool htable_copy_(struct htable *dst, const struct htable *src) { uintptr_t *htable = malloc(sizeof(size_t) << src->bits); @@ -122,21 +124,21 @@ static void *htable_val(const struct htable *ht, return NULL; } -void *htable_firstval(const struct htable *ht, - struct htable_iter *i, size_t hash) +void *htable_firstval_(const struct htable *ht, + struct htable_iter *i, size_t hash) { i->off = hash_bucket(ht, hash); return htable_val(ht, i, hash, ht->perfect_bit); } -void *htable_nextval(const struct htable *ht, - struct htable_iter *i, size_t hash) +void *htable_nextval_(const struct htable *ht, + struct htable_iter *i, size_t hash) { i->off = (i->off + 1) & ((1 << ht->bits)-1); return htable_val(ht, i, hash, 0); } -void *htable_first(const struct htable *ht, struct htable_iter *i) +void *htable_first_(const struct htable *ht, struct htable_iter *i) { for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) { if (entry_is_valid(ht->table[i->off])) @@ -145,7 +147,7 @@ void *htable_first(const struct htable *ht, struct htable_iter *i) return NULL; } -void *htable_next(const struct htable *ht, struct htable_iter *i) +void *htable_next_(const struct htable *ht, struct htable_iter *i) { for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) { if (entry_is_valid(ht->table[i->off])) @@ -154,7 +156,7 @@ void *htable_next(const struct htable *ht, struct htable_iter *i) return NULL; } -void *htable_prev(const struct htable *ht, struct htable_iter *i) +void *htable_prev_(const struct htable *ht, struct htable_iter *i) { for (;;) { if (!i->off) @@ -215,6 +217,8 @@ static COLD bool double_table(struct htable *ht) free(oldtable); } ht->deleted = 0; + + (void)htable_debug(ht, HTABLE_LOC); return true; } @@ -240,6 +244,7 @@ static COLD void rehash_table(struct htable *ht) } } ht->deleted = 0; + (void)htable_debug(ht, HTABLE_LOC); } /* We stole some bits, now we need to put them back... */ @@ -261,6 +266,7 @@ static COLD void update_common(struct htable *ht, const void *p) ht->common_mask = ~((uintptr_t)1 << i); ht->common_bits = ((uintptr_t)p & ht->common_mask); ht->perfect_bit = 1; + (void)htable_debug(ht, HTABLE_LOC); return; } @@ -283,9 +289,10 @@ static COLD void update_common(struct htable *ht, const void *p) ht->common_mask &= ~maskdiff; ht->common_bits &= ~maskdiff; ht->perfect_bit &= ~maskdiff; + (void)htable_debug(ht, HTABLE_LOC); } -bool htable_add(struct htable *ht, size_t hash, const void *p) +bool htable_add_(struct htable *ht, size_t hash, const void *p) { if (ht->elems+1 > ht->max && !double_table(ht)) return false; @@ -300,7 +307,7 @@ bool htable_add(struct htable *ht, size_t hash, const void *p) return true; } -bool htable_del(struct htable *ht, size_t h, const void *p) +bool htable_del_(struct htable *ht, size_t h, const void *p) { struct htable_iter i; void *c; @@ -314,7 +321,7 @@ bool htable_del(struct htable *ht, size_t h, const void *p) return false; } -void htable_delval(struct htable *ht, struct htable_iter *i) +void htable_delval_(struct htable *ht, struct htable_iter *i) { assert(i->off < (size_t)1 << ht->bits); assert(entry_is_valid(ht->table[i->off])); @@ -323,3 +330,53 @@ void htable_delval(struct htable *ht, struct htable_iter *i) ht->table[i->off] = HTABLE_DELETED; ht->deleted++; } + +struct htable *htable_check(const struct htable *ht, const char *abortstr) +{ + void *p; + struct htable_iter i; + size_t n = 0; + + /* Use non-DEBUG versions here, to avoid infinite recursion with + * CCAN_HTABLE_DEBUG! */ + for (p = htable_first_(ht, &i); p; p = htable_next_(ht, &i)) { + struct htable_iter i2; + void *c; + size_t h = ht->rehash(p, ht->priv); + bool found = false; + + n++; + + /* Open-code htable_get to avoid CCAN_HTABLE_DEBUG */ + for (c = htable_firstval_(ht, &i2, h); + c; + c = htable_nextval_(ht, &i2, h)) { + if (c == p) { + found = true; + break; + } + } + + if (!found) { + if (abortstr) { + fprintf(stderr, + "%s: element %p in position %zu" + " cannot find itself\n", + abortstr, p, i.off); + abort(); + } + return NULL; + } + } + if (n != ht->elems) { + if (abortstr) { + fprintf(stderr, + "%s: found %zu elems, expected %zu\n", + abortstr, n, ht->elems); + abort(); + } + return NULL; + } + + return (struct htable *)ht; +} diff --git a/ccan/ccan/htable/htable.h b/ccan/ccan/htable/htable.h index 9845388e1..53c447c09 100644 --- a/ccan/ccan/htable/htable.h +++ b/ccan/ccan/htable/htable.h @@ -2,10 +2,19 @@ #ifndef CCAN_HTABLE_H #define CCAN_HTABLE_H #include "config.h" +#include #include #include #include +/* Define CCAN_HTABLE_DEBUG for expensive debugging checks on each call. */ +#define HTABLE_LOC __FILE__ ":" stringify(__LINE__) +#ifdef CCAN_HTABLE_DEBUG +#define htable_debug(h, loc) htable_check((h), loc) +#else +#define htable_debug(h, loc) ((void)loc, h) +#endif + /** * struct htable - private definition of a htable. * @@ -75,6 +84,22 @@ bool htable_init_sized(struct htable *ht, */ void htable_clear(struct htable *ht); + +/** + * htable_check - check hash table for consistency + * @ht: the htable + * @abortstr: the location to print on aborting, or NULL. + * + * Because hash tables have redundant information, consistency checking that + * each element is in the correct location can be done. This is useful as a + * debugging check. If @abortstr is non-NULL, that will be printed in a + * diagnostic if the htable is inconsistent, and the function will abort. + * + * Returns the htable if it is consistent, NULL if not (it can never return + * NULL if @abortstr is set). + */ +struct htable *htable_check(const struct htable *ht, const char *abortstr); + /** * htable_copy - duplicate a hash table. * @dst: the hash table to overwrite @@ -92,14 +117,8 @@ void htable_clear(struct htable *ht); * } * return true; */ -bool htable_copy(struct htable *dst, const struct htable *src); - -/** - * htable_rehash - use a hashtree's rehash function - * @elem: the argument to rehash() - * - */ -size_t htable_rehash(const void *elem); +#define htable_copy(dst, src) htable_copy_(dst, htable_debug(src, HTABLE_LOC)) +bool htable_copy_(struct htable *dst, const struct htable *src); /** * htable_add - add a pointer into a hash table. @@ -110,7 +129,9 @@ size_t htable_rehash(const void *elem); * Also note that this can only fail due to allocation failure. Otherwise, it * returns true. */ -bool htable_add(struct htable *ht, size_t hash, const void *p); +#define htable_add(ht, hash, p) \ + htable_add_(htable_debug(ht, HTABLE_LOC), hash, p) +bool htable_add_(struct htable *ht, size_t hash, const void *p); /** * htable_del - remove a pointer from a hash table @@ -120,7 +141,9 @@ bool htable_add(struct htable *ht, size_t hash, const void *p); * * Returns true if the pointer was found (and deleted). */ -bool htable_del(struct htable *ht, size_t hash, const void *p); +#define htable_del(ht, hash, p) \ + htable_del_(htable_debug(ht, HTABLE_LOC), hash, p) +bool htable_del_(struct htable *ht, size_t hash, const void *p); /** * struct htable_iter - iterator or htable_first or htable_firstval etc. @@ -141,8 +164,11 @@ struct htable_iter { * See Also: * htable_delval() */ -void *htable_firstval(const struct htable *htable, - struct htable_iter *i, size_t hash); +#define htable_firstval(htable, i, hash) \ + htable_firstval_(htable_debug(htable, HTABLE_LOC), i, hash) + +void *htable_firstval_(const struct htable *htable, + struct htable_iter *i, size_t hash); /** * htable_nextval - find another candidate for a given hash value @@ -152,8 +178,10 @@ void *htable_firstval(const struct htable *htable, * * You'll need to check the value is what you want; returns NULL if no more. */ -void *htable_nextval(const struct htable *htable, - struct htable_iter *i, size_t hash); +#define htable_nextval(htable, i, hash) \ + htable_nextval_(htable_debug(htable, HTABLE_LOC), i, hash) +void *htable_nextval_(const struct htable *htable, + struct htable_iter *i, size_t hash); /** * htable_get - find an entry in the hash table @@ -186,7 +214,9 @@ static inline void *htable_get(const struct htable *ht, * * Get an entry in the hashtable; NULL if empty. */ -void *htable_first(const struct htable *htable, struct htable_iter *i); +#define htable_first(htable, i) \ + htable_first_(htable_debug(htable, HTABLE_LOC), i) +void *htable_first_(const struct htable *htable, struct htable_iter *i); /** * htable_next - find another entry in the hash table @@ -196,7 +226,9 @@ void *htable_first(const struct htable *htable, struct htable_iter *i); * Get another entry in the hashtable; NULL if all done. * This is usually used after htable_first or prior non-NULL htable_next. */ -void *htable_next(const struct htable *htable, struct htable_iter *i); +#define htable_next(htable, i) \ + htable_next_(htable_debug(htable, HTABLE_LOC), i) +void *htable_next_(const struct htable *htable, struct htable_iter *i); /** * htable_prev - find the previous entry in the hash table @@ -211,7 +243,9 @@ void *htable_next(const struct htable *htable, struct htable_iter *i); * This is usually used in the middle of (or after) a htable_next iteration and * to "unwind" actions taken. */ -void *htable_prev(const struct htable *htable, struct htable_iter *i); +#define htable_prev(htable, i) \ + htable_prev_(htable_debug(htable, HTABLE_LOC), i) +void *htable_prev_(const struct htable *htable, struct htable_iter *i); /** * htable_delval - remove an iterated pointer from a hash table @@ -221,6 +255,8 @@ void *htable_prev(const struct htable *htable, struct htable_iter *i); * Usually used to delete a hash entry after it has been found with * htable_firstval etc. */ -void htable_delval(struct htable *ht, struct htable_iter *i); +#define htable_delval(htable, i) \ + htable_delval_(htable_debug(htable, HTABLE_LOC), i) +void htable_delval_(struct htable *ht, struct htable_iter *i); #endif /* CCAN_HTABLE_H */ diff --git a/ccan/ccan/io/io.c b/ccan/ccan/io/io.c index c0dd9b838..bdcbf9e26 100644 --- a/ccan/ccan/io/io.c +++ b/ccan/ccan/io/io.c @@ -202,8 +202,12 @@ struct io_plan *io_write_(struct io_conn *conn, const void *data, size_t len, static int do_read(int fd, struct io_plan_arg *arg) { ssize_t ret = read(fd, arg->u1.cp, arg->u2.s); - if (ret <= 0) + if (ret <= 0) { + /* Errno isn't set if we hit EOF, so set it to distinct value */ + if (ret == 0) + errno = 0; return -1; + } arg->u1.cp += ret; arg->u2.s -= ret; @@ -230,8 +234,12 @@ struct io_plan *io_read_(struct io_conn *conn, static int do_read_partial(int fd, struct io_plan_arg *arg) { ssize_t ret = read(fd, arg->u1.cp, *(size_t *)arg->u2.vp); - if (ret <= 0) + if (ret <= 0) { + /* Errno isn't set if we hit EOF, so set it to distinct value */ + if (ret == 0) + errno = 0; return -1; + } *(size_t *)arg->u2.vp = ret; return 1; diff --git a/ccan/ccan/io/io.h b/ccan/ccan/io/io.h index c9ab228c7..510ee0be0 100644 --- a/ccan/ccan/io/io.h +++ b/ccan/ccan/io/io.h @@ -223,7 +223,8 @@ struct io_plan *io_write_(struct io_conn *conn, * * This creates a plan to read data into a buffer. Once it's all * read, the @next function will be called: on an error, the finish - * function is called instead. + * function is called instead. If read() returns 0 (EOF) errno is set + * to 0. * * Note that the I/O may actually be done immediately. * @@ -256,7 +257,8 @@ struct io_plan *io_read_(struct io_conn *conn, * * This creates a plan to read data into a buffer. Once any data is * read, @len is updated and the @next function will be called: on an - * error, the finish function is called instead. + * error, the finish function is called instead. If read() returns 0 (EOF) + * errno is set to 0. * * Note that the I/O may actually be done immediately. * diff --git a/ccan/ccan/io/test/run-45-eof.c b/ccan/ccan/io/test/run-45-eof.c new file mode 100644 index 000000000..6a7f99218 --- /dev/null +++ b/ccan/ccan/io/test/run-45-eof.c @@ -0,0 +1,45 @@ +#include +/* Include the C files directly. */ +#include +#include +#include +#include +#include + +static size_t len; + +static void finished_read(struct io_conn *conn, int *expect) +{ + ok1(errno == *expect); +} + +static struct io_plan *init_conn_read(struct io_conn *conn, int *expect) +{ + io_set_finish(conn, finished_read, expect); + return io_read(conn, &expect, sizeof(expect), io_never, expect); +} + +static struct io_plan *init_conn_read_partial(struct io_conn *conn, int *expect) +{ + io_set_finish(conn, finished_read, expect); + return io_read_partial(conn, &expect, sizeof(expect), &len, + io_never, expect); +} + +int main(void) +{ + int fd, expect_errno = 0; + + /* This is how many tests you plan to run */ + plan_tests(2); + fd = open("/dev/null", O_RDONLY); + io_new_conn(NULL, fd, init_conn_read, &expect_errno); + + fd = open("/dev/null", O_RDONLY); + io_new_conn(NULL, fd, init_conn_read_partial, &expect_errno); + + io_loop(NULL, NULL); + + /* This exits depending on whether all tests passed */ + return exit_status(); +} diff --git a/ccan/ccan/structeq/structeq.h b/ccan/ccan/structeq/structeq.h index 6b90754c7..81799539c 100644 --- a/ccan/ccan/structeq/structeq.h +++ b/ccan/ccan/structeq/structeq.h @@ -9,14 +9,15 @@ /** * STRUCTEQ_DEF - define an ..._eq function to compare two structures. * @sname: name of the structure, and function (_eq) to define. - * @padbytes: number of bytes of expected padding, or -1 if unknown. + * @padbytes: number of bytes of expected padding, or negative "max". * @...: name of every member of the structure. * * This generates a single memcmp() call in the common case where the * structure contains no padding. Since it can't tell the difference between * padding and a missing member, @padbytes can be used to assert that - * there isn't any, or how many we expect. -1 means "expect some", since - * it can be platform dependent. + * there isn't any, or how many we expect. A negative number means + * "up to or equal to that amount of padding", as padding can be + * platform dependent. */ #define STRUCTEQ_DEF(sname, padbytes, ...) \ static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \ @@ -25,7 +26,7 @@ static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \ BUILD_ASSERT(((padbytes) < 0 && \ CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \ __VA_ARGS__)) \ - > sizeof(*_a)) \ + - (padbytes) >= sizeof(*_a)) \ || CPPMAGIC_JOIN(+, CPPMAGIC_MAP(STRUCTEQ_MEMBER_SIZE_, \ __VA_ARGS__)) \ + (padbytes) == sizeof(*_a)); \ diff --git a/ccan/ccan/structeq/test/compile_fail-expect-any-padding.c b/ccan/ccan/structeq/test/compile_fail-expect-any-padding.c index 321aef3a3..182c86079 100644 --- a/ccan/ccan/structeq/test/compile_fail-expect-any-padding.c +++ b/ccan/ccan/structeq/test/compile_fail-expect-any-padding.c @@ -2,11 +2,12 @@ struct mydata { int start, end; + int pad; }; #ifdef FAIL -#define PADDING -1 +#define PADDING -1 /* We have more than 1 byte padding */ #else -#define PADDING 0 +#define PADDING sizeof(int) #endif STRUCTEQ_DEF(mydata, PADDING, start, end); diff --git a/ccan/ccan/structeq/test/compile_fail-unexpected-negative-padding.c b/ccan/ccan/structeq/test/compile_fail-unexpected-negative-padding.c new file mode 100644 index 000000000..2c63b23d9 --- /dev/null +++ b/ccan/ccan/structeq/test/compile_fail-unexpected-negative-padding.c @@ -0,0 +1,20 @@ +#include + +struct mydata { + int start, end; + int pad; +}; +#ifdef FAIL +#define PADDING -1 +#else +#define PADDING -(int)sizeof(int) +#endif + +STRUCTEQ_DEF(mydata, PADDING, start, end); + +int main(void) +{ + struct mydata a = { 0, 100 }; + + return mydata_eq(&a, &a); +} diff --git a/ccan/ccan/structeq/test/run-with-unknown-padding.c b/ccan/ccan/structeq/test/run-with-unknown-padding.c new file mode 100644 index 000000000..c803e722d --- /dev/null +++ b/ccan/ccan/structeq/test/run-with-unknown-padding.c @@ -0,0 +1,39 @@ +#include +#include + +/* In theory, this could be generated without padding, if alignof(int) were 0, + * and test would fail. Call me when that happens. */ +struct mydata { + char start; + int end; +}; + +STRUCTEQ_DEF(mydata, -3, start, end); + +struct mydata2 { + char start; + int end; +}; + +STRUCTEQ_DEF(mydata2, -4, start, end); + +int main(void) +{ + struct mydata a, b; + + /* This is how many tests you plan to run */ + plan_tests(3); + + a.start = 0; + a.end = 100; + ok1(mydata_eq(&a, &a)); + + b = a; + ok1(mydata_eq(&a, &b)); + + b.end++; + ok1(!mydata_eq(&a, &b)); + + /* This exits depending on whether all tests passed */ + return exit_status(); +}