diff --git a/ccan/README b/ccan/README index 80a88ad447a0..a5272fb35445 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from https://github.com/rustyrussell/ccan. -CCAN version: fe99a8e0 +CCAN version: 08af1cab diff --git a/ccan/ccan/asort/asort.c b/ccan/ccan/asort/asort.c index b90891ea199e..4607f907088f 100644 --- a/ccan/ccan/asort/asort.c +++ b/ccan/ccan/asort/asort.c @@ -34,11 +34,15 @@ #include #include +/* Vendored glibc code uses GNU void * arithmetic. */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpointer-arith" + /* glibc-internal type, mapped to ccan's equivalent. */ typedef _total_order_cb __compar_d_fn_t; /* glibc-internal helpers, not available outside glibc. */ -static inline void *__mempcpy(void *dst, const void *src, size_t n) +static inline void *asort_mempcpy(void *dst, const void *src, size_t n) { return (char *) memcpy (dst, src, n) + n; } @@ -54,8 +58,8 @@ __memswap (void *__restrict p1, void *__restrict p2, size_t n) while (n > SWAP_GENERIC_SIZE) { memcpy (tmp, p1, SWAP_GENERIC_SIZE); - p1 = __mempcpy (p1, p2, SWAP_GENERIC_SIZE); - p2 = __mempcpy (p2, tmp, SWAP_GENERIC_SIZE); + p1 = asort_mempcpy (p1, p2, SWAP_GENERIC_SIZE); + p2 = asort_mempcpy (p2, tmp, SWAP_GENERIC_SIZE); n -= SWAP_GENERIC_SIZE; } while (n > 0) @@ -316,13 +320,13 @@ msort_with_tmp (const struct msort_param *p, void *b, size_t n) { if (cmp (b1, b2, arg) <= 0) { - tmp = (char *) __mempcpy (tmp, b1, s); + tmp = (char *) asort_mempcpy (tmp, b1, s); b1 += s; --n1; } else { - tmp = (char *) __mempcpy (tmp, b2, s); + tmp = (char *) asort_mempcpy (tmp, b2, s); b2 += s; --n2; } @@ -452,4 +456,6 @@ _asort (void *const pbase, size_t total_elems, size_t size, } } +#pragma GCC diagnostic pop + #endif /* !HAVE_QSORT_R_PRIVATE_LAST */ diff --git a/ccan/ccan/asort/asort.h b/ccan/ccan/asort/asort.h index 43b0f89c3c6b..4f5ab24028da 100644 --- a/ccan/ccan/asort/asort.h +++ b/ccan/ccan/asort/asort.h @@ -23,6 +23,12 @@ _asort((base), (num), sizeof(*(base)), \ total_order_cast((cmp), *(base), (ctx)), (ctx)) #if HAVE_QSORT_R_PRIVATE_LAST +/* qsort_r is only declared under _GNU_SOURCE, which must precede the + * first libc include — we can't control our includers, so declare it + * ourselves (the configurator only sets this where this GNU signature + * was detected). */ +void qsort_r(void *base, size_t nmemb, size_t size, + int (*compar)(const void *, const void *, void *), void *arg); #define _asort(b, n, s, cmp, ctx) qsort_r(b, n, s, cmp, ctx) #else void _asort(void *base, size_t nmemb, size_t size, diff --git a/ccan/ccan/bitmap/bitmap.h b/ccan/ccan/bitmap/bitmap.h index e1bf4bb761d2..466fc867c848 100644 --- a/ccan/ccan/bitmap/bitmap.h +++ b/ccan/ccan/bitmap/bitmap.h @@ -13,7 +13,7 @@ typedef unsigned long bitmap_word; #define BITMAP_WORD_BITS (sizeof(bitmap_word) * CHAR_BIT) #define BITMAP_NWORDS(_n) \ - (((_n) + BITMAP_WORD_BITS - 1) / BITMAP_WORD_BITS) + (((_n) / BITMAP_WORD_BITS) + (((_n) % BITMAP_WORD_BITS) != 0)) #define BITMAP_WORD_0 (0) #define BITMAP_WORD_1 ((bitmap_word)-1UL) diff --git a/ccan/ccan/bitops/bitops.h b/ccan/ccan/bitops/bitops.h index 4e81f5716fb3..b2a3bc7f0e07 100644 --- a/ccan/ccan/bitops/bitops.h +++ b/ccan/ccan/bitops/bitops.h @@ -26,7 +26,7 @@ static inline int bitops_ffs32(uint32_t u) /** * bitops_ffs64: find lowest set bit in a uint64_t * - * Returns 1 for least significant bit, 32 for most significant bit, 0 + * Returns 1 for least significant bit, 64 for most significant bit, 0 * for no bits set. */ static inline int bitops_ffs64(uint64_t u) diff --git a/ccan/ccan/breakpoint/breakpoint.c b/ccan/ccan/breakpoint/breakpoint.c index 279e29a1dfd1..30532ec69a88 100644 --- a/ccan/ccan/breakpoint/breakpoint.c +++ b/ccan/ccan/breakpoint/breakpoint.c @@ -7,26 +7,39 @@ bool breakpoint_initialized; bool breakpoint_under_debug; +pid_t breakpoint_pid; + +static volatile sig_atomic_t trapped; /* This doesn't get called if we're under GDB. */ static void trap(int signum) { - breakpoint_initialized = true; + trapped = true; } void breakpoint_init(void) { struct sigaction old, new; + sigset_t mask, oldmask; new.sa_handler = trap; new.sa_flags = 0; sigemptyset(&new.sa_mask); sigaction(SIGTRAP, &new, &old); + + /* If SIGTRAP is blocked, the probe would pend (and kill us when + * the caller restores its mask), not run the handler. */ + sigemptyset(&mask); + sigaddset(&mask, SIGTRAP); + sigprocmask(SIG_UNBLOCK, &mask, &oldmask); + + trapped = false; kill(getpid(), SIGTRAP); + + sigprocmask(SIG_SETMASK, &oldmask, NULL); sigaction(SIGTRAP, &old, NULL); - if (!breakpoint_initialized) { - breakpoint_initialized = true; - breakpoint_under_debug = true; - } + breakpoint_pid = getpid(); + breakpoint_initialized = true; + breakpoint_under_debug = !trapped; } diff --git a/ccan/ccan/breakpoint/breakpoint.h b/ccan/ccan/breakpoint/breakpoint.h index 6283a01052a9..1a0c36d24845 100644 --- a/ccan/ccan/breakpoint/breakpoint.h +++ b/ccan/ccan/breakpoint/breakpoint.h @@ -10,13 +10,20 @@ void breakpoint_init(void) COLD; extern bool breakpoint_initialized; extern bool breakpoint_under_debug; +extern pid_t breakpoint_pid; /** * breakpoint - stop if running under the debugger. + * + * The first call detects the debugger via a SIGTRAP probe. This is + * not thread-safe: either call breakpoint_init() explicitly at + * program start (before creating threads), or don't let first use + * race. */ static inline void breakpoint(void) { - if (!breakpoint_initialized) + /* Detection state doesn't carry across fork(). */ + if (!breakpoint_initialized || breakpoint_pid != getpid()) breakpoint_init(); if (breakpoint_under_debug) kill(getpid(), SIGTRAP); diff --git a/ccan/ccan/build_assert/build_assert.h b/ccan/ccan/build_assert/build_assert.h index b9ecd84028e3..03ad7106a890 100644 --- a/ccan/ccan/build_assert/build_assert.h +++ b/ccan/ccan/build_assert/build_assert.h @@ -1,13 +1,19 @@ /* CC0 (Public domain) - see LICENSE file for details */ #ifndef CCAN_BUILD_ASSERT_H #define CCAN_BUILD_ASSERT_H +#include "config.h" /** * BUILD_ASSERT - assert a build-time dependency. * @cond: the compile-time condition which must be true. * - * Your compile will fail if the condition isn't true, or can't be evaluated - * by the compiler. This can only be used within a function. + * Your compile will fail if the condition isn't true. When the + * compiler supports C11 _Static_assert it will also fail if the + * condition can't be evaluated by the compiler; otherwise (older + * compilers) a non-constant condition is silently accepted (and is + * undefined behavior if false at runtime). + * + * This can only be used within a function. * * Example: * #include @@ -19,22 +25,38 @@ * return (char *)foo; * } */ +#if HAVE_STATIC_ASSERT +/* _Static_assert is a declaration, so do-while wrap avoids breaking if (x) BUILD_ASSERT... */ +#define BUILD_ASSERT(cond) \ + do { _Static_assert(cond, "BUILD_ASSERT"); } while(0) +#else #define BUILD_ASSERT(cond) \ do { (void) sizeof(char [1 - 2*!(cond)]); } while(0) +#endif /** * BUILD_ASSERT_OR_ZERO - assert a build-time dependency, as an expression. * @cond: the compile-time condition which must be true. * - * Your compile will fail if the condition isn't true, or can't be evaluated - * by the compiler. This can be used in an expression: its value is "0". + * Your compile will fail if the condition isn't true. When the + * compiler supports C11 _Static_assert it will also fail if the + * condition can't be evaluated by the compiler; otherwise (older + * compilers) a non-constant condition is silently accepted (and is + * undefined behavior if false at runtime). + * + * This can be used in an expression: its value is "0". * * Example: * #define foo_to_char(foo) \ * ((char *)(foo) \ * + BUILD_ASSERT_OR_ZERO(offsetof(struct foo, string) == 0)) */ +#if HAVE_STATIC_ASSERT +#define BUILD_ASSERT_OR_ZERO(cond) \ + (sizeof(struct { _Static_assert(cond, "BUILD_ASSERT_OR_ZERO"); char c; }) - 1) +#else #define BUILD_ASSERT_OR_ZERO(cond) \ (sizeof(char [1 - 2*!(cond)]) - 1) +#endif #endif /* CCAN_BUILD_ASSERT_H */ diff --git a/ccan/ccan/cdump/cdump.c b/ccan/ccan/cdump/cdump.c index 7e42dbd74dc6..50419c5d763a 100644 --- a/ccan/ccan/cdump/cdump.c +++ b/ccan/ccan/cdump/cdump.c @@ -48,9 +48,10 @@ static struct token *tokenize(const void *ctx, const char *code) } else if (code[i] == '/' && code[i+1] == '*') { /* Multi-line comment. */ const char *end = strstr(code+i+2, "*/"); - len = (end + 2) - (code + i); if (!end) len = strlen(code + i); + else + len = (end + 2) - (code + i); if (tok_start != -1U) { add_token(&toks, code+tok_start, i - tok_start); tok_start = -1U; @@ -82,6 +83,10 @@ static struct token *tokenize(const void *ctx, const char *code) start_of_line = false; } + /* A trailing identifier running to EOF is still a token. */ + if (tok_start != -1U) + add_token(&toks, code+tok_start, i - tok_start); + /* Add terminating NULL. */ tal_resizez(&toks, tal_count(toks) + 1); return toks; @@ -92,6 +97,7 @@ struct parse_state { const struct token *toks; struct cdump_definitions *defs; char *complaints; + unsigned int depth; }; static const struct token *tok_peek(const struct token **toks) @@ -277,17 +283,28 @@ static void tok_take_unknown_statement(struct parse_state *ps) static bool tok_take_expr(struct parse_state *ps, const char *term) { + /* Recursion is one frame per nested ( or [: bound it. */ + if (ps->depth++ == 100) { + complain(ps, "Expression nested too deeply"); + goto fail; + } while (!tok_is(&ps->toks, term)) { if (tok_take_if(&ps->toks, "(")) { if (!tok_take_expr(ps, ")")) - return false; + goto fail; } else if (tok_take_if(&ps->toks, "[")) { if (!tok_take_expr(ps, "]")) - return false; + goto fail; } else if (!tok_take(&ps->toks)) - return false; + goto fail; } - return tok_take(&ps->toks); + if (!tok_take(&ps->toks)) + goto fail; + ps->depth--; + return true; +fail: + ps->depth--; + return false; } static char *tok_take_expr_str(const tal_t *ctx, @@ -347,7 +364,12 @@ static bool tok_take_type(struct parse_state *ps, struct cdump_type **type) /* Did we get some? */ if (ps->toks != types) { - name = string_of_toks(NULL, types, tok_peek(&ps->toks)); + const struct token *until = tok_peek(&ps->toks); + if (!until) { + complain(ps, "EOF after type"); + return false; + } + name = string_of_toks(NULL, types, until); kind = CDUMP_UNKNOWN; } else { /* Try normal types (or simple typedefs, etc). */ @@ -654,6 +676,7 @@ struct cdump_definitions *cdump_extract(const tal_t *ctx, const char *code, ps.defs = tal(ctx, struct cdump_definitions); ps.complaints = tal_strdup(ctx, ""); ps.code = code; + ps.depth = 0; strmap_init(&ps.defs->enums); strmap_init(&ps.defs->structs); diff --git a/ccan/ccan/check_type/check_type.h b/ccan/ccan/check_type/check_type.h index 837aef7b1a36..a97d93d0a2b0 100644 --- a/ccan/ccan/check_type/check_type.h +++ b/ccan/ccan/check_type/check_type.h @@ -45,7 +45,15 @@ * ((encl_type *) \ * ((char *)(mbr_ptr) - offsetof(encl_type, mbr)))) */ -#if HAVE_TYPEOF +#if HAVE_TYPEOF && HAVE_BUILTIN_TYPES_COMPATIBLE_P +#include +#define check_type(expr, type) \ + BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(typeof(expr), type)) + +#define check_types_match(expr1, expr2) \ + BUILD_ASSERT_OR_ZERO(__builtin_types_compatible_p(typeof(expr1), \ + typeof(expr2))) +#elif HAVE_TYPEOF #define check_type(expr, type) \ ((typeof(expr) *)0 != (type *)0) diff --git a/ccan/ccan/compiler/compiler.h b/ccan/ccan/compiler/compiler.h index 562b29ec71cc..cdba22aa460a 100644 --- a/ccan/ccan/compiler/compiler.h +++ b/ccan/ccan/compiler/compiler.h @@ -75,6 +75,7 @@ #else #define CONST_FUNCTION #endif +#endif #ifndef PURE_FUNCTION #if HAVE_ATTRIBUTE_PURE @@ -89,7 +90,6 @@ #define PURE_FUNCTION #endif #endif -#endif #if HAVE_ATTRIBUTE_UNUSED #ifndef UNNEEDED @@ -199,7 +199,7 @@ * // Use inline if compiler knows answer. Otherwise call function * // to avoid copies of the same code everywhere. * #define greek_name(g) \ - * (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g)) + * (IS_COMPILE_CONSTANT(g) ? _greek_name(g) : greek_name(g)) */ #define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr) #else @@ -230,6 +230,7 @@ #endif +#ifndef WARN_DEPRECATED #if HAVE_ATTRIBUTE_DEPRECATED /** * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used. @@ -243,8 +244,9 @@ #else #define WARN_DEPRECATED #endif +#endif - +#ifndef NO_NULL_ARGS #if HAVE_ATTRIBUTE_NONNULL /** * NO_NULL_ARGS - specify that no arguments to this function can be NULL. @@ -255,7 +257,13 @@ * NO_NULL_ARGS char *my_copy(char *buf); */ #define NO_NULL_ARGS __attribute__((__nonnull__)) +#else +#define NO_NULL_ARGS +#endif +#endif +#ifndef NON_NULL_ARGS +#if HAVE_ATTRIBUTE_NONNULL /** * NON_NULL_ARGS - specify that some arguments to this function can't be NULL. * @...: 1-based argument numbers for which args can't be NULL. @@ -267,10 +275,11 @@ */ #define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__))) #else -#define NO_NULL_ARGS #define NON_NULL_ARGS(...) #endif +#endif +#ifndef RETURNS_NONNULL #if HAVE_ATTRIBUTE_RETURNS_NONNULL /** * RETURNS_NONNULL - specify that this function cannot return NULL. @@ -284,7 +293,9 @@ #else #define RETURNS_NONNULL #endif +#endif +#ifndef LAST_ARG_NULL #if HAVE_ATTRIBUTE_SENTINEL /** * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL. @@ -298,7 +309,9 @@ #else #define LAST_ARG_NULL #endif +#endif +#ifndef cpu_supports #if HAVE_BUILTIN_CPU_SUPPORTS /** * cpu_supports - test if current CPU supports the named feature. @@ -313,5 +326,6 @@ #else #define cpu_supports(x) 0 #endif /* HAVE_BUILTIN_CPU_SUPPORTS */ +#endif #endif /* CCAN_COMPILER_H */ diff --git a/ccan/ccan/container_of/container_of.h b/ccan/ccan/container_of/container_of.h index 47a34d853b4c..0487f55c32a6 100644 --- a/ccan/ccan/container_of/container_of.h +++ b/ccan/ccan/container_of/container_of.h @@ -68,9 +68,10 @@ static inline char *container_of_or_null_(void *member_ptr, size_t offset) } #define container_of_or_null(member_ptr, containing_type, member) \ ((containing_type *) \ - container_of_or_null_(member_ptr, \ - container_off(containing_type, member)) \ - + check_types_match(*(member_ptr), ((containing_type *)0)->member)) + ((void)check_types_match(*(member_ptr), \ + ((containing_type *)0)->member), \ + container_of_or_null_(member_ptr, \ + container_off(containing_type, member)))) /** * container_off - get offset to enclosing structure diff --git a/ccan/ccan/cppmagic/cppmagic.h b/ccan/ccan/cppmagic/cppmagic.h index f1f6868e550d..dee273610f33 100644 --- a/ccan/ccan/cppmagic/cppmagic.h +++ b/ccan/ccan/cppmagic/cppmagic.h @@ -46,7 +46,7 @@ * expands to '1' if @a is '0', otherwise expands to '0'. */ #define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0) -#define _CPPMAGIC_PROBE() $, 1 +#define _CPPMAGIC_PROBE() _cppmagic_probe, 1 #define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE() #define CPPMAGIC_ISZERO(a_) \ _CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_)) @@ -139,6 +139,11 @@ * * CPPMAGIC_MAP(@m, @a1, @a2, ... @an) * expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an) + * + * Note: an argument which expands to no tokens is not supported: it + * silently truncates the argument list at that point (before C23 + * __VA_OPT__ there is no way to distinguish "expands to nothing" + * from "absent"). */ #define _CPPMAGIC_MAP_() _CPPMAGIC_MAP #define _CPPMAGIC_MAP(m_, a_, ...) \ @@ -158,6 +163,9 @@ * CPPMAGIC_2MAP(@m, @a1, @b1, @a2, @b2, ..., @an, @bn) * expands to the expansion of * @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn) + * + * Note: an argument which expands to no tokens is not supported + * (see CPPMAGIC_MAP). */ #define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP #define _CPPMAGIC_2MAP(m_, a_, b_, ...) \ @@ -176,6 +184,9 @@ * * CPPMAGIC_JOIN(@d, @a1, @a2, ..., @an) * expands to the expansion of @a1 @d @a2 @d ... @d @an + * + * Note: an argument which expands to no tokens is not supported + * (see CPPMAGIC_MAP). */ #define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN #define _CPPMAGIC_JOIN(d_, a_, ...) \ diff --git a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c index f36bf67ade03..79d7ff434921 100644 --- a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c +++ b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.c @@ -13,7 +13,10 @@ void hkdf_sha256(void *okm, size_t okm_size, struct hmac_sha256_ctx ctx; unsigned char c; - assert(okm_size < 255 * sizeof(t)); + assert(okm_size <= 255 * sizeof(t)); + + if (okm_size == 0) + return; /* RFC 5869: * diff --git a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h index cf95c5afd8e7..b2905f1e6288 100644 --- a/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h +++ b/ccan/ccan/crypto/hkdf_sha256/hkdf_sha256.h @@ -7,7 +7,7 @@ /** * hkdf_sha256 - generate a derived key * @okm: where to output the key - * @okm_size: the number of bytes pointed to by @okm (must be less than 255*32) + * @okm_size: the number of bytes pointed to by @okm (must be at most 255*32) * @s: salt * @ssize: the number of bytes pointed to by @s * @k: pointer to input key diff --git a/ccan/ccan/crypto/sha256/sha256.h b/ccan/ccan/crypto/sha256/sha256.h index 9a310b9564c6..a7a0e86fd97b 100644 --- a/ccan/ccan/crypto/sha256/sha256.h +++ b/ccan/ccan/crypto/sha256/sha256.h @@ -49,7 +49,8 @@ struct sha256_ctx { uint32_t u32[16]; unsigned char u8[64]; } buf; - size_t bytes; + /* uint64_t: hashing 4GB+ must not wrap the length on 32-bit. */ + uint64_t bytes; #endif }; diff --git a/ccan/ccan/crypto/shachain/shachain.c b/ccan/ccan/crypto/shachain/shachain.c index 9cb54a37bdd9..1bf896a8a180 100644 --- a/ccan/ccan/crypto/shachain/shachain.c +++ b/ccan/ccan/crypto/shachain/shachain.c @@ -86,8 +86,17 @@ bool shachain_add_hash(struct shachain *chain, /* You have to insert them in order! */ assert(index == shachain_next_index(chain)); + /* Reject out-of-domain indices (SHACHAIN_BITS < 64 builds, and + * the post-exhaustion wrap to UINT64_MAX). */ + if (index > (UINT64_MAX >> (64 - SHACHAIN_BITS))) + return false; + pos = count_trailing_zeroes(index); + /* Beyond the chain domain (past exhaustion): no such slot. */ + if (pos > SHACHAIN_BITS) + return false; + /* All derivable answers must be valid. */ /* FIXME: Is it sufficient to check just the next answer? */ for (i = 0; i < pos; i++) { diff --git a/ccan/ccan/err/test/run.c b/ccan/ccan/err/test/run.c index aeaa3750b3d4..d4ebbeae5c7c 100644 --- a/ccan/ccan/err/test/run.c +++ b/ccan/ccan/err/test/run.c @@ -30,7 +30,6 @@ int main(int argc, char *argv[]) /* Test err() in child */ if (pipe(pfd)) abort(); - fflush(stdout); if (fork()) { char buffer[BUFFER_MAX+1]; unsigned int i; @@ -63,7 +62,6 @@ int main(int argc, char *argv[]) /* Test errx() in child */ if (pipe(pfd)) abort(); - fflush(stdout); if (fork()) { char buffer[BUFFER_MAX+1]; unsigned int i; @@ -94,7 +92,6 @@ int main(int argc, char *argv[]) /* Test warn() in child */ if (pipe(pfd)) abort(); - fflush(stdout); if (fork()) { char buffer[BUFFER_MAX+1]; unsigned int i; @@ -127,7 +124,6 @@ int main(int argc, char *argv[]) /* Test warnx() in child */ if (pipe(pfd)) abort(); - fflush(stdout); if (fork()) { char buffer[BUFFER_MAX+1]; unsigned int i; diff --git a/ccan/ccan/fdpass/fdpass.c b/ccan/ccan/fdpass/fdpass.c index af1a7fdb9ab0..c64ccc11ce8a 100644 --- a/ccan/ccan/fdpass/fdpass.c +++ b/ccan/ccan/fdpass/fdpass.c @@ -4,6 +4,7 @@ #include #include #include +#include bool fdpass_send(int sockout, int fd) { @@ -71,11 +72,24 @@ int fdpass_recv(int sockin) return -1; cmsg = CMSG_FIRSTHDR(&msg); - if (!cmsg - || cmsg->cmsg_len != CMSG_LEN(sizeof(fd)) + if (!cmsg || cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { - errno = -EINVAL; + errno = EINVAL; + return -1; + } + + if (cmsg->cmsg_len != CMSG_LEN(sizeof(fd))) { + /* The kernel already installed any fds the message + * carried; don't leak them. */ + if (cmsg->cmsg_len >= CMSG_LEN(0) + && cmsg->cmsg_len <= msg.msg_controllen) { + int *fds = (int *)CMSG_DATA(cmsg); + size_t i, nfds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + for (i = 0; i < nfds; i++) + close(fds[i]); + } + errno = EINVAL; return -1; } diff --git a/ccan/ccan/htable/htable.c b/ccan/ccan/htable/htable.c index 0b515b94bbf0..c28a36b4260c 100644 --- a/ccan/ccan/htable/htable.c +++ b/ccan/ccan/htable/htable.c @@ -86,6 +86,12 @@ void htable_init(struct htable *ht, ht->table = &ht->common_bits; } +/* Number of buckets in the table. */ +static inline size_t ht_size(const struct htable *ht) +{ + return (size_t)1 << ht->bits; +} + /* Fill to 87.5% */ static inline size_t ht_max(const struct htable *ht) { @@ -95,7 +101,7 @@ static inline size_t ht_max(const struct htable *ht) /* Clean deleted if we're full, and more than 12.5% deleted */ static inline size_t ht_max_deleted(const struct htable *ht) { - return ((size_t)1 << ht->bits) / 8; + return ht_size(ht) / 8; } bool htable_init_sized(struct htable *ht, @@ -108,11 +114,15 @@ bool htable_init_sized(struct htable *ht, for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) { if (ht->bits == 30) break; + /* Stop before the allocation size wraps (eg. 32-bit). */ + if ((sizeof(size_t) << (ht->bits + 1)) == 0) + break; } ht->table = htable_alloc(ht, sizeof(size_t) << ht->bits); if (!ht->table) { ht->table = &ht->common_bits; + ht->bits = 0; return false; } (void)htable_debug(ht, HTABLE_LOC); @@ -153,7 +163,7 @@ void htable_unlock(struct htable *ht) static size_t hash_bucket(const struct htable *ht, size_t h) { - return h & ((1 << ht->bits)-1); + return h & (ht_size(ht)-1); } static void *htable_val(const struct htable *ht, @@ -166,7 +176,7 @@ static void *htable_val(const struct htable *ht, if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2) return get_raw_ptr(ht, ht->table[i->off]); } - i->off = (i->off + 1) & ((1 << ht->bits)-1); + i->off = (i->off + 1) & (ht_size(ht)-1); h2 &= ~perfect; } return NULL; @@ -182,13 +192,13 @@ void *htable_firstval_(const struct htable *ht, void *htable_nextval_(const struct htable *ht, struct htable_iter *i, size_t hash) { - i->off = (i->off + 1) & ((1 << ht->bits)-1); + i->off = (i->off + 1) & (ht_size(ht)-1); return htable_val(ht, i, hash, 0); } void *htable_first_(const struct htable *ht, struct htable_iter *i) { - for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) { + for (i->off = 0; i->off < ht_size(ht); i->off++) { if (entry_is_valid(ht->table[i->off])) return get_raw_ptr(ht, ht->table[i->off]); } @@ -197,7 +207,7 @@ void *htable_first_(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++) { + for (i->off++; i->off < ht_size(ht); i->off++) { if (entry_is_valid(ht->table[i->off])) return get_raw_ptr(ht, ht->table[i->off]); } @@ -243,7 +253,7 @@ static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff) again: bitsdiff = ht->common_bits & maskdiff; - for (i = 0; i < (size_t)1 << ht->bits; i++) { + for (i = 0; i < ht_size(ht); i++) { uintptr_t e; if (!entry_is_valid(e = ht->table[i])) continue; @@ -296,7 +306,7 @@ static void ht_add(struct htable *ht, const void *new, size_t h) while (entry_is_valid(ht->table[i])) { perfect = 0; - i = (i + 1) & ((1 << ht->bits)-1); + i = (i + 1) & (ht_size(ht)-1); } ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect); if (!entry_is_valid(ht->table[i])) @@ -306,11 +316,16 @@ static void ht_add(struct htable *ht, const void *new, size_t h) static COLD bool double_table(struct htable *ht) { unsigned int i; - size_t oldnum = (size_t)1 << ht->bits; + size_t oldnum = ht_size(ht); + size_t newsize = sizeof(size_t) << (ht->bits+1); uintptr_t *oldtable, e; + /* 32-bit: doubling can wrap the allocation size to 0. */ + if (newsize == 0) + return false; + oldtable = ht->table; - ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1)); + ht->table = htable_alloc(ht, newsize); if (!ht->table) { ht->table = oldtable; return false; @@ -350,8 +365,8 @@ static COLD void rehash_table(struct htable *ht) /* Beware wrap cases: we need to start from first empty bucket. */ for (start = 0; ht->table[start]; start++); - for (i = 0; i < (size_t)1 << ht->bits; i++) { - size_t h = (i + start) & ((1 << ht->bits)-1); + for (i = 0; i < ht_size(ht); i++) { + size_t h = (i + start) & (ht_size(ht)-1); e = ht->table[h]; if (!e) continue; @@ -427,7 +442,7 @@ bool htable_del_(struct htable *ht, size_t h, const void *p) void htable_delval_(struct htable *ht, struct htable_iter *i) { - assert(i->off < (size_t)1 << ht->bits); + assert(i->off < ht_size(ht)); assert(entry_is_valid(ht->table[i->off])); ht->elems--; @@ -446,7 +461,7 @@ void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i) if (!i) i = &unwanted; - i->off = seed % ((size_t)1 << ht->bits); + i->off = seed % ht_size(ht); e = htable_next(ht, i); if (!e) e = htable_first(ht, i); diff --git a/ccan/ccan/ilog/ilog.h b/ccan/ccan/ilog/ilog.h index 32702b178567..960e89f78fa3 100644 --- a/ccan/ccan/ilog/ilog.h +++ b/ccan/ccan/ilog/ilog.h @@ -131,7 +131,7 @@ int ilog64_nz(uint64_t _v) CONST_FUNCTION; #endif /* builtin_ilog32_nz */ #ifdef builtin_ilog64_nz -#define ilog32(_v) ((_v) ? builtin_ilog32_nz(_v) : 0) +#define ilog64(_v) ((_v) ? builtin_ilog64_nz(_v) : 0) #define ilog64_nz(_v) builtin_ilog64_nz(_v) #else #define ilog64_nz(_v) ilog64(_v) diff --git a/ccan/ccan/intmap/intmap.h b/ccan/ccan/intmap/intmap.h index 834c969fa7c7..6cc4c59bd44b 100644 --- a/ccan/ccan/intmap/intmap.h +++ b/ccan/ccan/intmap/intmap.h @@ -467,7 +467,8 @@ static inline void *sintmap_first_(const struct intmap *map, { intmap_index_t i; void *ret = intmap_first_(map, &i); - *indexp = SINTMAP_UNOFF(i); + if (ret) + *indexp = SINTMAP_UNOFF(i); return ret; } @@ -495,7 +496,8 @@ static inline void *sintmap_last_(const struct intmap *map, { intmap_index_t i; void *ret = intmap_last_(map, &i); - *indexp = SINTMAP_UNOFF(i); + if (ret) + *indexp = SINTMAP_UNOFF(i); return ret; } diff --git a/ccan/ccan/io/io.c b/ccan/ccan/io/io.c index baa9a497cc56..c4ad9cac5898 100644 --- a/ccan/ccan/io/io.c +++ b/ccan/ccan/io/io.c @@ -33,6 +33,11 @@ struct io_listener *io_new_listener_(const tal_t *ctx, int fd, l->ctx = ctx; if (!add_listener(l)) return tal_free(l); + + /* Keep accept() async: a connection which vanishes between + * poll() and accept() (eg. peer RST) must not block the loop. */ + io_fd_block(fd, false); + return l; } diff --git a/ccan/ccan/io/poll.c b/ccan/ccan/io/poll.c index c4cbaee85678..dd21dbc1e6e3 100644 --- a/ccan/ccan/io/poll.c +++ b/ccan/ccan/io/poll.c @@ -310,6 +310,18 @@ static bool handle_always(void) return false; } +/* Is there an always plan we can actually run right now? */ +static bool always_runnable(void) +{ + size_t i; + + for (i = 0; i < num_always; i++) { + if (!num_exclusive || *exclusive(always[i])) + return true; + } + return false; +} + bool backend_set_exclusive(struct io_plan *plan, bool excl) { bool *excl_ptr = exclusive(plan); @@ -374,7 +386,7 @@ void *io_loop(struct timers *timers, struct timer **expired) { void *ret; /* This ensures we don't always service lower fds first */ - static int fairness_counter; + static size_t fairness_counter; /* if timers is NULL, expired must be. If not, not. */ assert(!timers == !expired); @@ -415,7 +427,7 @@ void *io_loop(struct timers *timers, struct timer **expired) } /* Don't wait if we have always requests pending! */ - if (num_always != 0) + if (always_runnable()) ms_timeout = 0; /* We do this temporarily, assuming exclusive is unusual */ diff --git a/ccan/ccan/json_escape/json_escape.c b/ccan/ccan/json_escape/json_escape.c index 6344bd8a8985..ce748a12d881 100644 --- a/ccan/ccan/json_escape/json_escape.c +++ b/ccan/ccan/json_escape/json_escape.c @@ -61,6 +61,8 @@ static struct json_escape *escape(const tal_t *ctx, /* Worst case: all \uXXXX */ esc = (struct json_escape *)tal_arr(ctx, char, len * 6 + 1); + if (!esc) + return NULL; for (i = n = 0; i < len; i++, n++) { char escape = 0; diff --git a/ccan/ccan/json_out/json_out.c b/ccan/ccan/json_out/json_out.c index 915d525ef406..4b018bc96644 100644 --- a/ccan/ccan/json_out/json_out.c +++ b/ccan/ccan/json_out/json_out.c @@ -115,7 +115,8 @@ static void unindent(struct json_out *jout, char type) jout->empty = false; } -/* Make sure jout->outbuf has room for len: return pointer */ +/* Make sure jout->outbuf has room for len: return pointer, or NULL + * if the allocation failed. */ static char *mkroom(struct json_out *jout, size_t len) { ptrdiff_t delta = membuf_prepare_space(&jout->outbuf, len); @@ -123,6 +124,11 @@ static char *mkroom(struct json_out *jout, size_t len) if (delta && jout->move_cb) jout->move_cb(jout, delta, jout->cb_arg); + /* membuf_prepare_space() documents checking membuf_num_space() + * to detect allocation failure. */ + if (membuf_num_space(&jout->outbuf) < len) + return NULL; + return membuf_space(&jout->outbuf); } @@ -218,6 +224,7 @@ bool json_out_addv(struct json_out *jout, size_t fmtlen, avail; va_list ap2; char *dst; + int vsnprintf_ret; if (!json_out_member_direct(jout, fieldname, 0)) return false; @@ -236,7 +243,12 @@ bool json_out_addv(struct json_out *jout, /* Try printing in place first. */ dst = membuf_space(&jout->outbuf); - fmtlen = vsnprintf(dst + quote, avail, fmt, ap); + vsnprintf_ret = vsnprintf(dst + quote, avail, fmt, ap); + if (vsnprintf_ret < 0) { + dst = NULL; + goto out; + } + fmtlen = vsnprintf_ret; /* Horrible subtlety: vsnprintf *will* NUL terminate, even if it means * chopping off the last character. So if fmtlen == @@ -259,6 +271,10 @@ bool json_out_addv(struct json_out *jout, if (json_escape_needed(dst + quote, fmtlen)) { struct json_escape *e; e = json_escape_len(NULL, dst + quote, fmtlen); + if (!e) { + dst = NULL; + goto out; + } fmtlen = strlen(e->s); dst = mkroom(jout, fmtlen + (int)quote*2); if (!dst) @@ -307,6 +323,8 @@ bool json_out_addstrn(struct json_out *jout, if (json_escape_needed(str, len)) { e = json_escape_len(NULL, str, len); + if (!e) + return false; str = e->s; len = strlen(str); } else @@ -328,11 +346,15 @@ bool json_out_add_splice(struct json_out *jout, { const char *p; size_t len; + char *dst; p = json_out_contents(src, &len); if (!p) return false; - memcpy(json_out_member_direct(jout, fieldname, len), p, len); + dst = json_out_member_direct(jout, fieldname, len); + if (!dst) + return false; + memcpy(dst, p, len); return true; } diff --git a/ccan/ccan/likely/likely.c b/ccan/ccan/likely/likely.c index aabb51ed2471..d015a37931a8 100644 --- a/ccan/ccan/likely/likely.c +++ b/ccan/ccan/likely/likely.c @@ -99,7 +99,7 @@ char *likely_stats(unsigned int min_hits, unsigned int percent) } } - if (worst_ratio * 100 > percent) + if (!worst || worst_ratio * 100 > percent) return NULL; maxlen = strlen(worst->condstr) + diff --git a/ccan/ccan/mem/mem.c b/ccan/ccan/mem/mem.c index 13027a2a7b0f..ddb84c9d108a 100644 --- a/ccan/ccan/mem/mem.c +++ b/ccan/ccan/mem/mem.c @@ -33,7 +33,7 @@ void *memrchr(const void *s, int c, size_t n) unsigned char *p = (unsigned char *)s; while (n) { - if (p[n-1] == c) + if (p[n-1] == (unsigned char)c) return p + n - 1; n--; } @@ -56,11 +56,11 @@ void *mempbrkm(const void *data_, size_t len, const void *accept_, size_t accept void *memcchr(void const *data, int c, size_t data_len) { - char const *p = data; + unsigned char const *p = data; size_t i; for (i = 0; i < data_len; i++) - if (p[i] != c) + if (p[i] != (unsigned char)c) return (void *)&p[i]; return NULL; diff --git a/ccan/ccan/mem/mem.h b/ccan/ccan/mem/mem.h index 20286dcbefd4..2c61b92d6fc5 100644 --- a/ccan/ccan/mem/mem.h +++ b/ccan/ccan/mem/mem.h @@ -219,6 +219,9 @@ static inline bool memends_str(const void *a, size_t al, const char *s) * @al: length of first memory range * @b: pointer to second memory range * @al: length of second memory range + * + * Note that a zero-length range counts as overlapping any range that + * straddles its address. */ CONST_FUNCTION static inline bool memoverlaps(const void *a_, size_t al, diff --git a/ccan/ccan/mem/test/api.c b/ccan/ccan/mem/test/api.c index 59b25947ab0a..f7dc28d9e884 100644 --- a/ccan/ccan/mem/test/api.c +++ b/ccan/ccan/mem/test/api.c @@ -1,6 +1,7 @@ #include "config.h" #include +#include #include #include @@ -96,8 +97,11 @@ int main(void) haystack1 + sizeof(haystack1), 1)); ok1(!memoverlaps(haystack1 + sizeof(haystack1), 1, haystack1, sizeof(haystack1))); - ok1(!memoverlaps(haystack1, sizeof(haystack1), haystack1 - 1, 1)); - ok1(!memoverlaps(haystack1 - 1, 1, haystack1, sizeof(haystack1))); + /* Forming haystack1 - 1 directly is UB; round-trip via uintptr_t. */ + ok1(!memoverlaps(haystack1, sizeof(haystack1), + (void *)((uintptr_t)haystack1 - 1), 1)); + ok1(!memoverlaps((void *)((uintptr_t)haystack1 - 1), 1, + haystack1, sizeof(haystack1))); ok1(memoverlaps(haystack1, 5, haystack1 + 4, 7)); ok1(!memoverlaps(haystack1, 5, haystack1 + 5, 6)); ok1(memoverlaps(haystack1 + 4, 7, haystack1, 5)); diff --git a/ccan/ccan/membuf/membuf.c b/ccan/ccan/membuf/membuf.c index 39841d9705a5..6d49b74894be 100644 --- a/ccan/ccan/membuf/membuf.c +++ b/ccan/ccan/membuf/membuf.c @@ -3,6 +3,7 @@ #include #include #include +#include void membuf_init_(struct membuf *mb, void *elems, size_t num_elems, size_t elemsize, @@ -42,6 +43,12 @@ size_t membuf_prepare_space_(struct membuf *mb, if (num_extra < mb->max_elems) num_extra = mb->max_elems; + /* Don't let the allocation size wrap. */ + if (num_extra > SIZE_MAX / elemsize - mb->max_elems) { + errno = ENOMEM; + return 0; + } + expand = mb->expandfn(mb, mb->elems, (mb->max_elems + num_extra) * elemsize); if (!expand) { @@ -51,6 +58,9 @@ size_t membuf_prepare_space_(struct membuf *mb, mb->elems = expand; } } + /* Nothing moved if there was no old buffer. */ + if (!oldstart) + return 0; return (char *)membuf_elems_(mb, elemsize) - oldstart; } diff --git a/ccan/ccan/membuf/membuf.h b/ccan/ccan/membuf/membuf.h index aebfca27d4f1..52a7bd02f186 100644 --- a/ccan/ccan/membuf/membuf.h +++ b/ccan/ccan/membuf/membuf.h @@ -83,6 +83,8 @@ static inline size_t membuf_num_elems_(const struct membuf *mb) static inline void *membuf_elems_(const struct membuf *mb, size_t elemsize) { + if (!mb->elems) + return NULL; return mb->elems + mb->start * elemsize; } @@ -130,6 +132,8 @@ static inline size_t membuf_num_space_(const struct membuf *mb) static inline void *membuf_space_(struct membuf *mb, size_t elemsize) { + if (!mb->elems) + return NULL; return mb->elems + mb->end * elemsize; } diff --git a/ccan/ccan/opt/helpers.c b/ccan/ccan/opt/helpers.c index 5db87bba3b04..5a71be26c569 100644 --- a/ccan/ccan/opt/helpers.c +++ b/ccan/ccan/opt/helpers.c @@ -60,8 +60,7 @@ char *opt_set_charp(const char *arg, char **p) return NULL; } -/* Set an integer value, various forms. - FIXME: set to 1 on arg == NULL ? */ +/* Set an integer value, various forms. */ char *opt_set_intval(const char *arg, int *i) { long l; diff --git a/ccan/ccan/opt/opt.h b/ccan/ccan/opt/opt.h index d6f5634e9b50..60204acae923 100644 --- a/ccan/ccan/opt/opt.h +++ b/ccan/ccan/opt/opt.h @@ -447,14 +447,14 @@ char *opt_set_charp(const char *arg, char **p); /* If *p is NULL, this returns false (i.e. doesn't show a default) */ bool opt_show_charp(char *buf, size_t len, char *const *p); -/* Set an integer value, various forms. Sets to 1 on arg == NULL. */ -char *opt_set_intval(const char *arg, int *i); +/* Set an integer value, various forms. */ +char *opt_set_intval(const char *arg, int *i) NO_NULL_ARGS; bool opt_show_intval(char *buf, size_t len, const int *i); -char *opt_set_uintval(const char *arg, unsigned int *ui); +char *opt_set_uintval(const char *arg, unsigned int *ui) NO_NULL_ARGS; bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui); -char *opt_set_longval(const char *arg, long *l); +char *opt_set_longval(const char *arg, long *l) NO_NULL_ARGS; bool opt_show_longval(char *buf, size_t len, const long *l); -char *opt_set_ulongval(const char *arg, unsigned long *ul); +char *opt_set_ulongval(const char *arg, unsigned long *ul) NO_NULL_ARGS; bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul); /* Set an floating point value, various forms. */ diff --git a/ccan/ccan/opt/parse.c b/ccan/ccan/opt/parse.c index b932bf333571..7bf31cb3d97d 100644 --- a/ccan/ccan/opt/parse.c +++ b/ccan/ccan/opt/parse.c @@ -92,12 +92,13 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset, arg = 1; } else { for (arg = 1; argv[arg]; arg++) { - if (argv[arg][0] == '-') + if (argv[arg][0] == '-' && argv[arg][1]) break; } } - if (!argv[arg] || argv[arg][0] != '-') + /* A bare '-' is an operand, not an option. */ + if (!argv[arg] || argv[arg][0] != '-' || argv[arg][1] == '\0') return 0; /* Special arg terminator option. */ diff --git a/ccan/ccan/order/test/run-fancy.c b/ccan/ccan/order/test/run-fancy.c index 5a287c4cbcfc..fbd6ac72de0f 100644 --- a/ccan/ccan/order/test/run-fancy.c +++ b/ccan/ccan/order/test/run-fancy.c @@ -56,13 +56,13 @@ int main(void) ok1(total_order_cmp(order2, &item2, &item2) == 0); ok1(total_order_cmp(order2, &item3, &item3) == 0); - ok1(total_order_cmp(order2, &item1, &item2) == 1); + ok1(total_order_cmp(order2, &item1, &item2) == -1); ok1(total_order_cmp(order2, &item2, &item3) == 1); ok1(total_order_cmp(order2, &item1, &item3) == 1); - ok1(total_order_cmp(order2, &item2, &item1) == -1); + ok1(total_order_cmp(order2, &item2, &item1) == 1); ok1(total_order_cmp(order2, &item3, &item2) == -1); ok1(total_order_cmp(order2, &item3, &item1) == -1); - - exit(0); + + return exit_status(); } diff --git a/ccan/ccan/pipecmd/pipecmd.c b/ccan/ccan/pipecmd/pipecmd.c index 0090275b0155..80447707e3f6 100644 --- a/ccan/ccan/pipecmd/pipecmd.c +++ b/ccan/ccan/pipecmd/pipecmd.c @@ -54,6 +54,7 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, int child_close[4], num_child_close = 0; pid_t childpid; int err; + ssize_t r; if (fd_tochild) { if (fd_tochild == &pipecmd_preserve) { @@ -164,7 +165,9 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, if (write(execfail[1], &err, sizeof(err))) { ; } - exit(127); + /* _exit: don't flush the parent's stdio buffers again, + * nor run its atexit handlers. */ + _exit(127); } int i; @@ -172,9 +175,22 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, close(par_close[i]); /* Child will close this without writing on successful exec. */ - if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) { + do { + r = read(execfail[0], &err, sizeof(err)); + } while (r < 0 && errno == EINTR); + + if (r == sizeof(err)) { close(execfail[0]); - waitpid(childpid, NULL, 0); + /* Useless now: close the parent-side pipe ends too. */ + if (fd_tochild && fd_tochild != &pipecmd_preserve) + close(tochild[1]); + if (fd_fromchild && fd_fromchild != &pipecmd_preserve) + close(fromchild[0]); + if (fd_errfromchild && fd_errfromchild != &pipecmd_preserve + && fd_errfromchild != fd_fromchild) + close(errfromchild[0]); + while (waitpid(childpid, NULL, 0) < 0 && errno == EINTR) + ; errno = err; return -1; } @@ -190,6 +206,8 @@ pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, fail: for (i = 0; i < num_par_close; i++) close_noerr(par_close[i]); + for (i = 0; i < num_child_close; i++) + close_noerr(child_close[i]); return -1; } diff --git a/ccan/ccan/ptr_valid/ptr_valid.c b/ccan/ccan/ptr_valid/ptr_valid.c index 7931984023ce..ff7ee040fb16 100644 --- a/ccan/ccan/ptr_valid/ptr_valid.c +++ b/ccan/ccan/ptr_valid/ptr_valid.c @@ -28,9 +28,10 @@ static char *grab(const char *filename) while ((ret = read(fd, buffer + s, max - s)) > 0) { s += ret; if (s == max) { - buffer = realloc(buffer, max*2+1); - if (!buffer) - goto close; + char *nb = realloc(buffer, max*2+1); + if (!nb) + goto free; + buffer = nb; max *= 2; } } @@ -62,10 +63,14 @@ static struct ptr_valid_map *add_map(struct ptr_valid_map *map, unsigned long start, unsigned long end, bool is_write) { if (*num == *max) { + struct ptr_valid_map *newmap; *max *= 2; - map = realloc(map, sizeof(*map) * *max); - if (!map) + newmap = realloc(map, sizeof(*newmap) * *max); + if (!newmap) { + free(map); return NULL; + } + map = newmap; } map[*num].start = (void *)start; map[*num].end = (void *)end; @@ -182,9 +187,9 @@ static void run_child(int infd, int outfd) /* This is weird. */ if (read(infd, &size, sizeof(size)) != sizeof(size)) - exit(1); + _exit(1); if (read(infd, &is_write, sizeof(is_write)) != sizeof(is_write)) - exit(2); + _exit(2); for (i = 0; i < size; i++) { ret = p[i]; @@ -194,9 +199,9 @@ static void run_child(int infd, int outfd) /* If we're still here, the answer is "yes". */ if (write(outfd, &ret, 1) != 1) - exit(3); + _exit(3); } - exit(0); + _exit(0); } static bool create_child(struct ptr_valid_batch *batch) @@ -271,16 +276,22 @@ bool ptr_valid_batch(struct ptr_valid_batch *batch, char *start, *end; bool ret; - if ((intptr_t)p & (alignment - 1)) + if ((intptr_t)p & (alignment - 1)) { + errno = EFAULT; return false; + } start = (void *)((intptr_t)p & ~(getpagesize() - 1)); end = (void *)(((intptr_t)p + size - 1) & ~(getpagesize() - 1)); /* We cache single page hits. */ if (start == end) { - if (batch->last && batch->last == start) + if (batch->last && batch->last == start + && batch->last_write == write) { + if (!batch->last_ok) + errno = EFAULT; return batch->last_ok; + } } if (batch->num_maps) @@ -291,8 +302,11 @@ bool ptr_valid_batch(struct ptr_valid_batch *batch, if (start == end) { batch->last = start; batch->last_ok = ret; + batch->last_write = write; } + if (!ret) + errno = EFAULT; return ret; } diff --git a/ccan/ccan/ptr_valid/ptr_valid.h b/ccan/ccan/ptr_valid/ptr_valid.h index 3871cad8e7e4..ad9a2e9c7c3b 100644 --- a/ccan/ccan/ptr_valid/ptr_valid.h +++ b/ccan/ccan/ptr_valid/ptr_valid.h @@ -80,6 +80,7 @@ struct ptr_valid_batch { int to_child, from_child; void *last; bool last_ok; + bool last_write; }; /** diff --git a/ccan/ccan/rbuf/rbuf.c b/ccan/ccan/rbuf/rbuf.c index cc10cf3d7f25..742373853dc9 100644 --- a/ccan/ccan/rbuf/rbuf.c +++ b/ccan/ccan/rbuf/rbuf.c @@ -62,8 +62,14 @@ void *rbuf_fill_all(struct rbuf *rbuf) void *rbuf_fill(struct rbuf *rbuf) { if (!rbuf_len(rbuf)) { - if (get_more(rbuf) < 0) + ssize_t r = get_more(rbuf); + if (r < 0) + return NULL; + /* EOF: documented NULL with errno 0. */ + if (r == 0) { + errno = 0; return NULL; + } } return rbuf_start(rbuf); } diff --git a/ccan/ccan/rune/coding.c b/ccan/ccan/rune/coding.c index 495d37c34e31..016b0ac9e32f 100644 --- a/ccan/ccan/rune/coding.c +++ b/ccan/ccan/rune/coding.c @@ -206,7 +206,8 @@ bool rune_condition_is_valid(enum rune_condition cond) size_t rune_altern_fieldname_len(const char *alternstr, size_t alternstrlen) { for (size_t i = 0; i < alternstrlen; i++) { - if (cispunct(alternstr[i]) && alternstr[i] != '_') + if (cispunct(alternstr[i]) && alternstr[i] != '_' + && alternstr[i] != '-' && alternstr[i] != '.') return i; } return alternstrlen; diff --git a/ccan/ccan/rune/rune.c b/ccan/ccan/rune/rune.c index 7937f8cb5329..4a6dd52092e1 100644 --- a/ccan/ccan/rune/rune.c +++ b/ccan/ccan/rune/rune.c @@ -70,6 +70,10 @@ struct rune *rune_dup(const tal_t *ctx, const struct rune *rune TAKES) return tal_steal(ctx, (struct rune *)rune); dup = tal_dup(ctx, struct rune, rune); + if (rune->unique_id) + dup->unique_id = tal_strdup(dup, rune->unique_id); + if (rune->version) + dup->version = tal_strdup(dup, rune->version); dup->restrs = tal_arr(dup, struct rune_restr *, tal_count(rune->restrs)); for (size_t i = 0; i < tal_count(rune->restrs); i++) { dup->restrs[i] = rune_restr_dup(dup->restrs, @@ -287,11 +291,16 @@ static int lexo_order(const char *fieldval_str, size_t fieldval_strlen, const char *alt) { - int ret = strncmp(fieldval_str, alt, fieldval_strlen); - - /* If alt is same but longer, fieldval is < */ - if (ret == 0 && strlen(alt) > fieldval_strlen) - ret = -1; + size_t altlen = strlen(alt); + size_t minlen = fieldval_strlen < altlen ? fieldval_strlen : altlen; + int ret = memcmp(fieldval_str, alt, minlen); + + if (ret == 0) { + if (fieldval_strlen < altlen) + ret = -1; + else if (fieldval_strlen > altlen) + ret = 1; + } return ret; } diff --git a/ccan/ccan/short_types/_info b/ccan/ccan/short_types/_info index 909e4e3aed0e..36ec05582bc9 100644 --- a/ccan/ccan/short_types/_info +++ b/ccan/ccan/short_types/_info @@ -40,7 +40,7 @@ * *size_total += size; * } * - * #define EVALUATE(psx, short, pt, st, t) \ + * #define EVALUATE(psx, sht, pt, st, t) \ * evaluate(sizeof(psx), stringify(psx), stringify(sht), pt, st, t) * * int main(void) diff --git a/ccan/ccan/str/base32/base32.c b/ccan/ccan/str/base32/base32.c index 6145da300765..91849d31d131 100644 --- a/ccan/ccan/str/base32/base32.c +++ b/ccan/ccan/str/base32/base32.c @@ -153,7 +153,7 @@ bool base32_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) destsize -= 8; dest += 8; } - if (destsize != 1) + if (destsize < 1) return false; *dest = '\0'; return true; diff --git a/ccan/ccan/str/hex/_info b/ccan/ccan/str/hex/_info index d70a1425e845..0a597516e320 100644 --- a/ccan/ccan/str/hex/_info +++ b/ccan/ccan/str/hex/_info @@ -18,7 +18,7 @@ * for (i = 1; i < argc; i++) { * char str[hex_str_size(strlen(argv[i]))]; * - * hex_encode(str, sizeof(str), argv[i], strlen(argv[i])); + * hex_encode(argv[i], strlen(argv[i]), str, sizeof(str)); * printf("%s ", str); * } * printf("\n"); diff --git a/ccan/ccan/str/str.c b/ccan/ccan/str/str.c index a9245c1742ec..a012c1d03aec 100644 --- a/ccan/ccan/str/str.c +++ b/ccan/ccan/str/str.c @@ -5,6 +5,9 @@ size_t strcount(const char *haystack, const char *needle) { size_t i = 0, nlen = strlen(needle); + if (nlen == 0) + return 0; + while ((haystack = strstr(haystack, needle)) != NULL) { i++; haystack += nlen; diff --git a/ccan/ccan/strmap/_info b/ccan/ccan/strmap/_info index eba8fe444ae7..094521af3797 100644 --- a/ccan/ccan/strmap/_info +++ b/ccan/ccan/strmap/_info @@ -53,6 +53,7 @@ int main(int argc, char *argv[]) if (strcmp(argv[1], "depends") == 0) { printf("ccan/ilog\n" + "ccan/mem\n" "ccan/short_types\n" "ccan/str\n" "ccan/tcon\n" diff --git a/ccan/ccan/strmap/strmap.c b/ccan/ccan/strmap/strmap.c index 16a30e036ad4..c711beb9ebae 100644 --- a/ccan/ccan/strmap/strmap.c +++ b/ccan/ccan/strmap/strmap.c @@ -2,9 +2,11 @@ #include #include #include +#include #include #include #include +#include #include struct node { @@ -42,7 +44,7 @@ void *strmap_getn_(const struct strmap *map, /* Not empty map? */ if (map->u.n) { n = closest((struct strmap *)map, member, memberlen); - if (!strncmp(member, n->u.s, memberlen) && !n->u.s[memberlen]) + if (memeqstr(member, memberlen, n->u.s)) return n->v; } errno = ENOENT; @@ -178,26 +180,119 @@ char *strmap_del_(struct strmap *map, const char *member, void **valuep) return (char *)ret; } -static bool iterate(struct strmap n, - bool (*handle)(const char *, void *, void *), - const void *data) +/* Defer child[1] of a node we're descending past. */ +static void iter_push(struct strmap_iter *it, struct strmap *slot) { - if (n.v) - return handle(n.u.s, n.v, (void *)data); + if (STRMAP_NUM_ITER_PARENTS == 0) { + it->dropped = true; + return; + } + if (it->num_parents == STRMAP_NUM_ITER_PARENTS) { + /* Full: drop the *shallowest* deferral (kept in-order by + * the slow path once the stack runs out). */ + memmove(&it->parents[0], &it->parents[1], + sizeof(it->parents[0]) * (STRMAP_NUM_ITER_PARENTS - 1)); + it->num_parents--; + it->dropped = true; + } + it->parents[it->num_parents++] = slot; +} + +/* Descend leftmost from *slot, deferring child[1]s, and yield the leaf. */ +static const char *iter_descend(struct strmap_iter *it, struct strmap *slot, + void **valuep) +{ + while (!slot->v) { + iter_push(it, &slot->u.n->child[1]); + slot = &slot->u.n->child[0]; + } + *valuep = slot->v; + return slot->u.s; +} + +/* Successor of cur by value: O(depth), no stack. */ +static const char *iter_successor(const struct strmap *map, + const char *cur, void **valuep) +{ + size_t len = strlen(cur); + const u8 *bytes = (const u8 *)cur; + struct strmap n, cand; + bool have_cand = false; + + n = *(struct strmap *)map; + while (!n.v) { + u8 c = 0, direction; + + if (n.u.n->byte_num < len) + c = bytes[n.u.n->byte_num]; + direction = (c >> n.u.n->bit_num) & 1; + if (direction == 0) { + /* Everything in child[1] sorts after child[0]. */ + cand = n.u.n->child[1]; + have_cand = true; + } + n = n.u.n->child[direction]; + } + + if (!have_cand) + return NULL; + + /* Leftmost member of the deepest candidate subtree. */ + while (!cand.v) + cand = cand.u.n->child[0]; + *valuep = cand.v; + return cand.u.s; +} + +const char *strmap_iter_first_(struct strmap_iter *it, + const struct strmap *map, void **valuep) +{ + it->num_parents = 0; + it->dropped = false; + it->slow_mode = false; + + if (!map->u.n) + return NULL; + + return iter_descend(it, (struct strmap *)map, valuep); +} + +const char *strmap_iter_next_(struct strmap_iter *it, + const struct strmap *map, const char *cur, + void **valuep) +{ + struct strmap *slot; - return iterate(n.u.n->child[0], handle, data) - && iterate(n.u.n->child[1], handle, data); + if (!it->slow_mode) { + if (it->num_parents != 0) { + slot = it->parents[--it->num_parents]; + return iter_descend(it, slot, valuep); + } + if (!it->dropped) + return NULL; + /* We dropped deferrals past STRMAP_NUM_ITER_PARENTS; + * from here on, find successors by re-descent. */ + it->dropped = false; + it->slow_mode = true; + } + + return iter_successor(map, cur, valuep); } void strmap_iterate_(const struct strmap *map, bool (*handle)(const char *, void *, void *), const void *data) { - /* Empty map? */ - if (!map->u.n) - return; - - iterate(*map, handle, data); + struct strmap_iter it; + const char *m; + void *v; + + for (m = strmap_iter_first_(&it, map, &v); + m; + m = strmap_iter_next_(&it, map, m, &v)) { + if (!handle(m, v, (void *)data)) + break; + } } const struct strmap *strmap_prefix_(const struct strmap *map, @@ -235,6 +330,7 @@ const struct strmap *strmap_prefix_(const struct strmap *map, return top; } +/* Recursive fallback for strmap_clear_'s OOM path. */ static void clear(struct strmap n) { if (!n.v) { @@ -246,7 +342,75 @@ static void clear(struct strmap n) void strmap_clear_(struct strmap *map) { - if (map->u.n) - clear(*map); + uintptr_t inline_stack[STRMAP_NUM_ITER_PARENTS]; + uintptr_t *stack = inline_stack; + size_t num = 0, max = STRMAP_NUM_ITER_PARENTS; + uintptr_t cur; + bool have_cur; + + if (!map->u.n) + return; + + /* Post-order without recursion: slot pointers tagged in their + * low bits (0 = visit child[0], 1 = visit child[1], 2 = free). */ + cur = (uintptr_t)map; + have_cur = true; + + while (have_cur || num) { + struct strmap *slot; + unsigned int tag; + + if (!have_cur) + cur = stack[--num]; + have_cur = false; + slot = (struct strmap *)(cur & ~(uintptr_t)3); + tag = cur & 3; + + if (slot->v) { + /* Leaf: caller-owned, keep. */ + continue; + } + if (tag == 2) { + free(slot->u.n); + continue; + } + + /* tag 0 or 1: requeue for the next phase, then descend. */ + { + struct strmap *child = &slot->u.n->child[tag]; + + if (num == max) { + uintptr_t *ns; + size_t nmax = max ? max * 2 : 64; + + if (stack == inline_stack) { + ns = malloc(nmax * sizeof(*ns)); + if (ns) + memcpy(ns, stack, + num * sizeof(*ns)); + } else { + ns = realloc(stack, nmax * sizeof(*ns)); + } + if (ns) { + stack = ns; + max = nmax; + } else { + /* OOM: finish this subtree + * recursively. */ + clear(*child); + if (tag == 0) + clear(slot->u.n->child[1]); + free(slot->u.n); + continue; + } + } + stack[num++] = (uintptr_t)slot | (tag + 1); + cur = (uintptr_t)child; + have_cur = true; + } + } + + if (stack != inline_stack) + free(stack); map->u.n = NULL; } diff --git a/ccan/ccan/strmap/strmap.h b/ccan/ccan/strmap/strmap.h index 8724c31dcbb2..800f78c70b00 100644 --- a/ccan/ccan/strmap/strmap.h +++ b/ccan/ccan/strmap/strmap.h @@ -5,6 +5,7 @@ #include #include #include +#include /** * struct strmap - representation of a string map @@ -204,6 +205,75 @@ void strmap_iterate_(const struct strmap *map, bool (*handle)(const char *, void *, void *), const void *data); +#ifndef STRMAP_NUM_ITER_PARENTS +#define STRMAP_NUM_ITER_PARENTS 16 +#endif + +/** + * struct strmap_iter - state for strmap_iter_first/strmap_iter_next. + * + * This is exposed so you can declare it on the stack. It holds up to + * STRMAP_NUM_ITER_PARENTS deferred subtrees; in trees deeper than + * that, iteration falls back to re-descending from the root (an + * O(depth) successor search per step), so memory use stays bounded + * for arbitrarily deep trees. + */ +struct strmap_iter { + struct strmap *parents[STRMAP_NUM_ITER_PARENTS]; + uint16_t num_parents; + bool dropped; + bool slow_mode; +}; + +/** + * strmap_iter_first - begin an ordered iteration over a map. + * @it: the iterator to initialize. + * @map: the typed strmap to iterate. + * @valuep: a pointer to a value to fill in. + * + * Returns the first member, and sets *@valuep, or returns NULL if the + * map is empty. You should not alter the map during iteration! + * + * Example: + * static void dump_map_iter(const STRMAP(int *) *map) + * { + * struct strmap_iter it; + * const char *m; + * int *v; + * + * for (m = strmap_iter_first(&it, map, &v); + * m; + * m = strmap_iter_next(&it, map, m, &v)) + * printf("%s=>%i\n", m, *v); + * } + */ +#define strmap_iter_first(it, map, valuep) \ + strmap_iter_first_((it), \ + tcon_unwrap(tcon_check_ptr((map), canary, \ + (valuep))), \ + (void *)(valuep)) +const char *strmap_iter_first_(struct strmap_iter *it, + const struct strmap *map, void **valuep); + +/** + * strmap_iter_next - continue an ordered iteration. + * @it: the iterator, initialized by strmap_iter_first(). + * @map: the typed strmap. + * @cur: the member the iteration is currently on. + * @valuep: a pointer to a value to fill in. + * + * Returns the next member, and sets *@valuep, or NULL at the end of + * the map. + */ +#define strmap_iter_next(it, map, cur, valuep) \ + strmap_iter_next_((it), \ + tcon_unwrap(tcon_check_ptr((map), canary, \ + (valuep))), \ + (cur), (void *)(valuep)) +const char *strmap_iter_next_(struct strmap_iter *it, + const struct strmap *map, const char *cur, + void **valuep); + /** * strmap_prefix - return a submap matching a prefix * @map: the map. diff --git a/ccan/ccan/strset/strset.c b/ccan/ccan/strset/strset.c index 06b0d7a76c35..5d5dc86dd82f 100644 --- a/ccan/ccan/strset/strset.c +++ b/ccan/ccan/strset/strset.c @@ -19,6 +19,7 @@ #include #include #include +#include #include struct node { @@ -228,26 +229,127 @@ char *strset_del(struct strset *set, const char *member) return (char *)ret; } -static bool iterate(struct strset n, - bool (*handle)(const char *, void *), const void *data) +void strset_iterate_(const struct strset *set, + bool (*handle)(const char *, void *), const void *data) { - if (n.u.s[0]) - return handle(n.u.s, (void *)data); - if (unlikely(n.u.n->byte_num == (size_t)-1)) - return handle(n.u.n->child[0].u.s, (void *)data); + struct strset_iter it; + const char *m; - return iterate(n.u.n->child[0], handle, data) - && iterate(n.u.n->child[1], handle, data); + for (m = strset_iter_first(&it, set); + m; + m = strset_iter_next(&it, set, m)) { + if (!handle(m, (void *)data)) + break; + } } -void strset_iterate_(const struct strset *set, - bool (*handle)(const char *, void *), const void *data) +/* Defer child[1] of a node we're descending past. */ +static void iter_push(struct strset_iter *it, struct strset *slot) { - /* Empty set? */ - if (!set->u.n) + if (STRSET_NUM_ITER_PARENTS == 0) { + it->dropped = true; return; + } + if (it->num_parents == STRSET_NUM_ITER_PARENTS) { + /* Full: drop the *shallowest* deferral (kept in-order by + * the slow_mode path once the stack runs out). */ + memmove(&it->parents[0], &it->parents[1], + sizeof(it->parents[0]) * (STRSET_NUM_ITER_PARENTS - 1)); + it->num_parents--; + it->dropped = true; + } + it->parents[it->num_parents++] = slot; +} - iterate(*set, handle, data); +/* Descend leftmost from *slot, deferring child[1]s, and yield the leaf. */ +static const char *iter_descend(struct strset_iter *it, struct strset *slot) +{ + while (!slot->u.s[0]) { + /* Empty-string node: the string is child[0]. */ + if (unlikely(slot->u.n->byte_num == (size_t)-1)) { + slot = &slot->u.n->child[0]; + break; + } + iter_push(it, &slot->u.n->child[1]); + slot = &slot->u.n->child[0]; + } + return slot->u.s; +} + +/* Successor of cur by value: O(depth), no stack. */ +static const char *iter_successor(const struct strset *set, + const char *cur) +{ + size_t len = strlen(cur); + const u8 *bytes = (const u8 *)cur; + struct strset n, cand; + bool have_cand = false; + + n = *(struct strset *)set; + while (!n.u.s[0]) { + u8 c = 0, direction; + + /* Empty-string node: only holds "" in child[0]. */ + if (unlikely(n.u.n->byte_num == (size_t)-1)) + break; + if (n.u.n->byte_num < len) + c = bytes[n.u.n->byte_num]; + direction = (c >> n.u.n->bit_num) & 1; + if (direction == 0) { + /* Everything in child[1] sorts after child[0]. */ + cand = n.u.n->child[1]; + have_cand = true; + } + n = n.u.n->child[direction]; + } + + if (!have_cand) + return NULL; + + /* Leftmost member of the deepest candidate subtree. */ + while (!cand.u.s[0]) { + if (unlikely(cand.u.n->byte_num == (size_t)-1)) { + cand = cand.u.n->child[0]; + break; + } + cand = cand.u.n->child[0]; + } + return cand.u.s; +} + +const char *strset_iter_first(struct strset_iter *it, + const struct strset *set) +{ + it->num_parents = 0; + it->dropped = false; + it->slow_mode = false; + + if (!set->u.n) + return NULL; + + return iter_descend(it, (struct strset *)set); +} + +const char *strset_iter_next(struct strset_iter *it, + const struct strset *set, + const char *cur) +{ + struct strset *slot; + + if (likely(!it->slow_mode)) { + if (it->num_parents != 0) { + slot = it->parents[--it->num_parents]; + return iter_descend(it, slot); + } + if (!it->dropped) + return NULL; + /* We dropped deferrals past STRSET_NUM_ITER_PARENTS; + * from here on, find successors by re-descent. */ + it->dropped = false; + it->slow_mode = true; + } + + return iter_successor(set, cur); } const struct strset *strset_prefix(const struct strset *set, const char *prefix) @@ -290,6 +392,7 @@ const struct strset *strset_prefix(const struct strset *set, const char *prefix) return top; } +/* Recursive fallback for strset_clear's OOM path. */ static void clear(struct strset n) { if (!n.u.s[0]) { @@ -303,7 +406,81 @@ static void clear(struct strset n) void strset_clear(struct strset *set) { - if (set->u.n) - clear(*set); + uintptr_t inline_stack[STRSET_NUM_ITER_PARENTS]; + uintptr_t *stack = inline_stack; + size_t num = 0, max = STRSET_NUM_ITER_PARENTS; + uintptr_t cur; + bool have_cur; + + if (!set->u.n) + return; + + /* Post-order without recursion: slot pointers tagged in their + * low bits (0 = visit child[0], 1 = visit child[1], 2 = free). */ + cur = (uintptr_t)set; + have_cur = true; + + while (have_cur || num) { + struct strset *slot; + unsigned int tag; + + if (!have_cur) + cur = stack[--num]; + have_cur = false; + slot = (struct strset *)(cur & ~(uintptr_t)3); + tag = cur & 3; + + if (slot->u.s[0]) { + /* Leaf: caller-owned, keep. */ + continue; + } + if (unlikely(slot->u.n->byte_num == (size_t)-1)) { + /* Empty-string node: child[0] is the caller-owned + * string itself; child[1] is unused. */ + free(slot->u.n); + continue; + } + if (tag == 2) { + free(slot->u.n); + continue; + } + + /* tag 0 or 1: requeue for the next phase, then descend. */ + { + struct strset *child = &slot->u.n->child[tag]; + + if (num == max) { + uintptr_t *ns; + size_t nmax = max ? max * 2 : 64; + + if (stack == inline_stack) { + ns = malloc(nmax * sizeof(*ns)); + if (ns) + memcpy(ns, stack, + num * sizeof(*ns)); + } else { + ns = realloc(stack, nmax * sizeof(*ns)); + } + if (ns) { + stack = ns; + max = nmax; + } else { + /* OOM: finish this subtree + * recursively. */ + clear(*child); + if (tag == 0) + clear(slot->u.n->child[1]); + free(slot->u.n); + continue; + } + } + stack[num++] = (uintptr_t)slot | (tag + 1); + cur = (uintptr_t)child; + have_cur = true; + } + } + + if (stack != inline_stack) + free(stack); set->u.n = NULL; } diff --git a/ccan/ccan/strset/strset.h b/ccan/ccan/strset/strset.h index 9d6f1ae343f5..1141051a58b6 100644 --- a/ccan/ccan/strset/strset.h +++ b/ccan/ccan/strset/strset.h @@ -4,6 +4,7 @@ #include #include #include +#include /** * struct strset - representation of a string set @@ -141,6 +142,61 @@ void strset_clear(struct strset *set); void strset_iterate_(const struct strset *set, bool (*handle)(const char *, void *), const void *data); +#ifndef STRSET_NUM_ITER_PARENTS +#define STRSET_NUM_ITER_PARENTS 16 +#endif + +/** + * struct strset_iter - state for strset_iter_first/strset_iter_next. + * + * This is exposed so you can declare it on the stack. It holds up to + * STRSET_NUM_ITER_PARENTS deferred subtrees; in trees deeper than + * that, iteration falls back to re-descending from the root (an + * O(depth) successor search per step), so memory use stays bounded + * for arbitrarily deep trees. + */ +struct strset_iter { + struct strset *parents[STRSET_NUM_ITER_PARENTS]; + uint16_t num_parents; + bool dropped; + bool slow_mode; +}; + +/** + * strset_iter_first - begin an ordered iteration over a set. + * @it: the iterator to initialize. + * @set: the set. + * + * Returns the first member, or NULL if the set is empty. + * You should not alter the set during iteration! + * + * Example: + * static void dump_set_iter(const struct strset *set) + * { + * struct strset_iter it; + * const char *m; + * + * for (m = strset_iter_first(&it, set); + * m; + * m = strset_iter_next(&it, set, m)) + * printf("%s\n", m); + * } + */ +const char *strset_iter_first(struct strset_iter *it, + const struct strset *set); + +/** + * strset_iter_next - continue an ordered iteration. + * @it: the iterator, initialized by strset_iter_first(). + * @set: the set. + * @cur: the member the iteration is currently on. + * + * Returns the next member, or NULL at the end of the set. + */ +const char *strset_iter_next(struct strset_iter *it, + const struct strset *set, + const char *cur); + /** * strset_prefix - return a subset matching a prefix diff --git a/ccan/ccan/structeq/structeq.h b/ccan/ccan/structeq/structeq.h index 81799539c51e..b035521914b0 100644 --- a/ccan/ccan/structeq/structeq.h +++ b/ccan/ccan/structeq/structeq.h @@ -18,6 +18,10 @@ * 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. + * + * Note that members which are themselves structures or unions are + * compared with memcmp(), so any *internal* padding they contain can + * cause false negatives, just like top-level padding would. */ #define STRUCTEQ_DEF(sname, padbytes, ...) \ static inline bool CPPMAGIC_GLUE2(sname, _eq)(const struct sname *_a, \ diff --git a/ccan/ccan/take/take.c b/ccan/ccan/take/take.c index 437855a27c75..83890f45e80f 100644 --- a/ccan/ccan/take/take.c +++ b/ccan/ccan/take/take.c @@ -81,6 +81,10 @@ bool taken(const void *p) memmove(&takenarr[i-1], &takenarr[i], (--num_taken - (i - 1))*sizeof(takenarr[0])); + if (labelarr) { + memmove(&labelarr[i-1], &labelarr[i], + (num_taken - (i - 1))*sizeof(labelarr[0])); + } return true; } @@ -114,6 +118,7 @@ const char *taken_any(void) void take_cleanup(void) { max_taken = num_taken = 0; + allocfail = 0; free(takenarr); takenarr = NULL; free(labelarr); diff --git a/ccan/ccan/tal/grab_file/grab_file.c b/ccan/ccan/tal/grab_file/grab_file.c index fcadc8334362..ee34a912af79 100644 --- a/ccan/ccan/tal/grab_file/grab_file.c +++ b/ccan/ccan/tal/grab_file/grab_file.c @@ -17,9 +17,11 @@ static void *grab_fd_internal(const void *ctx, int fd, bool add_nul_term) size = 0; - if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode)) + if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && st.st_size != 0) max = st.st_size; else + /* Non-regular file, or one reporting a zero size despite + * having content (eg. /proc, /sys): guess and grow. */ max = 16384; buffer = tal_arr(ctx, char, max+add_nul_term); diff --git a/ccan/ccan/tal/link/link.h b/ccan/ccan/tal/link/link.h index 1919253ca496..e5fc2be6f638 100644 --- a/ccan/ccan/tal/link/link.h +++ b/ccan/ccan/tal/link/link.h @@ -11,6 +11,9 @@ * The object will be freed when @newobj is freed or the last tal_link() * is tal_delink'ed. * + * Note: @newobj must not be tal_free()'d or tal_steal()'d while it has + * links: that aborts. Remove all links first. + * * Returns @newobj or NULL (if an allocation fails). * * Example: diff --git a/ccan/ccan/tal/path/path.c b/ccan/ccan/tal/path/path.c index 75894240b49d..941bcd781fa3 100644 --- a/ccan/ccan/tal/path/path.c +++ b/ccan/ccan/tal/path/path.c @@ -321,7 +321,8 @@ char *path_rel(const tal_t *ctx, const char *from, const char *to) break; } - if (!tal_resize(&ret, maxlen *= 2 + 1)) + maxlen = maxlen * 2 + 1; + if (!tal_resize(&ret, maxlen)) goto fail; } @@ -393,8 +394,12 @@ char *path_simplify(const tal_t *ctx, const char *path) j = sep - ret + 1; else j = 0; + continue; } - continue; + /* Symlink or nonexistent: can't safely step + * back, so keep the ".." literally. */ + ret[j-1] = PATH_SEP; + goto copy; } else if (start) { /* /.. => / */ j = 1; @@ -436,20 +441,27 @@ char *path_basename(const tal_t *ctx, const char *path) /* Trailing slashes need to be trimmed. */ if (!sep[1]) { - const char *end; + size_t end, sep_off; - for (end = sep; end != path; end--) - if (*end != PATH_SEP) + for (end = sep - path; end != 0; end--) + if (path[end] != PATH_SEP) break; - /* Find *previous* / */ - for (sep = end; sep >= path && *sep != PATH_SEP; sep--); + /* Find *previous* / ((size_t)-1 if there is none) */ + for (sep_off = end; ; sep_off--) { + if (path[sep_off] == PATH_SEP) + break; + if (sep_off == 0) { + sep_off = (size_t)-1; + break; + } + } /* All /? Just return / */ - if (end == sep) + if (end == sep_off) ret = tal_strdup(ctx, PATH_SEP_STR); else - ret = tal_strndup(ctx, sep+1, end - sep); + ret = tal_strndup(ctx, path + (sep_off + 1), end - sep_off); } else ret = tal_strdup(ctx, sep + 1); diff --git a/ccan/ccan/tal/path/path.h b/ccan/ccan/tal/path/path.h index 2f7f608b2388..586b48e37854 100644 --- a/ccan/ccan/tal/path/path.h +++ b/ccan/ccan/tal/path/path.h @@ -52,6 +52,9 @@ char *path_simplify(const tal_t *ctx, const char *a TAKES); * * If @a is an absolute path, return a copy of it. Otherwise, attach * @a to @base. + * + * @base and @a must not be NULL, except as the taken result of a + * failed take() chain (e.g. path_join(ctx, take(tal_fmt(...)), "x")). */ char *path_join(const tal_t *ctx, const char *base TAKES, const char *a TAKES); diff --git a/ccan/ccan/tal/path/test/run-simplify.c b/ccan/ccan/tal/path/test/run-simplify.c index 9591132dcf81..6b3570103412 100644 --- a/ccan/ccan/tal/path/test/run-simplify.c +++ b/ccan/ccan/tal/path/test/run-simplify.c @@ -6,7 +6,7 @@ int main(void) { char cwd[1024], *path, *ctx = tal_strdup(NULL, "ctx"); - plan_tests(85); + plan_tests(95); if (!getcwd(cwd, sizeof(cwd))) abort(); @@ -227,6 +227,33 @@ int main(void) ok1(tal_parent(path) == ctx); tal_free(path); + /* Don't trace back over a symlink: keep ".." literally. */ + path = path_simplify(ctx, "run-simplify-link/.."); + ok1(streq(path, "run-simplify-link/..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-link/../"); + ok1(streq(path, "run-simplify-link/..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-link/../x"); + ok1(streq(path, "run-simplify-link/../x")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + path = path_simplify(ctx, "run-simplify-link/../../foo"); + ok1(streq(path, "run-simplify-link/../../foo")); + ok1(tal_parent(path) == ctx); + tal_free(path); + + /* Nonexistent path: can't prove it's a real dir, keep "..". */ + path = path_simplify(ctx, "run-simplify-nosuch/.."); + ok1(streq(path, "run-simplify-nosuch/..")); + ok1(tal_parent(path) == ctx); + tal_free(path); + /* take tests */ path = path_simplify(ctx, take(tal_strdup(ctx, "/tmp/../tmp/."))); ok1(streq(path, "/tmp")); diff --git a/ccan/ccan/tal/str/str.c b/ccan/ccan/tal/str/str.c index 617b942cd8d0..67bddab4b831 100644 --- a/ccan/ccan/tal/str/str.c +++ b/ccan/ccan/tal/str/str.c @@ -150,8 +150,11 @@ char **tal_strsplit_(const tal_t *ctx, if (flags == STR_EMPTY_OK && dlen) dlen = 1; str += len + dlen; - if (++num == max && !tal_resize(&parts, max*=2 + 1)) - goto fail; + if (++num == max) { + max = max * 2 + 1; + if (!tal_resize(&parts, max)) + goto fail; + } } parts[num] = NULL; @@ -214,33 +217,9 @@ char *tal_strjoin_(const tal_t *ctx, goto out; } -static size_t count_open_braces(const char *string) -{ -#if 1 - size_t num = 0, esc = 0; - - while (*string) { - if (*string == '\\') - esc++; - else { - /* An odd number of \ means it's escaped. */ - if (*string == '(' && (esc & 1) == 0) - num++; - esc = 0; - } - string++; - } - return num; -#else - return strcount(string, "("); -#endif -} - bool tal_strreg_(const tal_t *ctx, const char *string, const char *label, const char *regex, ...) { - size_t nmatch = 1 + count_open_braces(regex); - regmatch_t matches[nmatch]; regex_t r; bool ret = false; unsigned int i; @@ -249,33 +228,39 @@ bool tal_strreg_(const tal_t *ctx, const char *string, const char *label, if (regcomp(&r, regex, REG_EXTENDED) != 0) goto fail_no_re; - if (regexec(&r, string, nmatch, matches, 0) != 0) - goto fail; - - ret = true; - va_start(ap, regex); - for (i = 1; i < nmatch; i++) { - char **arg = va_arg(ap, char **); - if (arg) { - /* eg. ([a-z])? can give "no match". */ - if (matches[i].rm_so == -1) - *arg = NULL; - else { - *arg = tal_strndup_(ctx, - string + matches[i].rm_so, - matches[i].rm_eo - - matches[i].rm_so, - label); - /* FIXME: If we fail, we set some and leak! */ - if (!*arg) { - ret = false; - break; + { + /* re_nsub counts real capture groups: unlike scanning the + * regex text, it is not fooled by '(' inside bracket + * expressions. */ + size_t nmatch = 1 + r.re_nsub; + regmatch_t matches[nmatch]; + + if (regexec(&r, string, nmatch, matches, 0) == 0) { + ret = true; + va_start(ap, regex); + for (i = 1; i < nmatch; i++) { + char **arg = va_arg(ap, char **); + if (arg) { + /* eg. ([a-z])? can give "no match". */ + if (matches[i].rm_so == -1) + *arg = NULL; + else { + *arg = tal_strndup_(ctx, + string + matches[i].rm_so, + matches[i].rm_eo + - matches[i].rm_so, + label); + /* FIXME: If we fail, we set some and leak! */ + if (!*arg) { + ret = false; + break; + } + } } } + va_end(ap); } } - va_end(ap); -fail: regfree(&r); fail_no_re: if (taken(regex)) diff --git a/ccan/ccan/tal/tal.c b/ccan/ccan/tal/tal.c index 39eb21537f4f..53358fda8265 100644 --- a/ccan/ccan/tal/tal.c +++ b/ccan/ccan/tal/tal.c @@ -244,6 +244,9 @@ static void notify(const struct tal_hdr *ctx, EXTRA_ARG(n)); else cb.destroy(from_tal_hdr(ctx)); + /* Restore: object may have been rescued by a + * tal_steal() from inside the destructor. */ + n->u = cb; } else n->u.notifyfn(from_tal_hdr_or_null(ctx), type, (void *)info); @@ -420,22 +423,26 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child) return true; } -static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) +static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno); + +/* Free t's children, properties and t itself. The destroying bit is + * already set (by del_tree() or tal_free()). */ +static void del_tree_inner(struct tal_hdr *t, const tal_t *orig, + int saved_errno) { struct prop_hdr *prop; char *ptr, *next; assert(!taken(from_tal_hdr(t))); - /* Already being destroyed? Don't loop. */ - if (unlikely(get_destroying_bit(t->parent_child))) - return; - - set_destroying_bit(&t->parent_child); - /* Call free notifiers. */ notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno); + /* A destructor/notifier can rescue the object by tal_steal()ing + * it elsewhere: add_child() clears the destroying bit. */ + if (!get_destroying_bit(t->parent_child)) + return; + /* Now free children and groups. */ prop = find_property(t, CHILDREN); if (prop) { @@ -456,6 +463,16 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) freefn(t); } +static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno) +{ + /* Already being destroyed? Don't loop. */ + if (unlikely(get_destroying_bit(t->parent_child))) + return; + + set_destroying_bit(&t->parent_child); + del_tree_inner(t, orig, saved_errno); +} + /* Don't have compiler complain we're returning NULL if we promised not to! */ static void *null_alloc_failed(void) { @@ -525,11 +542,21 @@ void *tal_free(const tal_t *ctx) t = debug_tal(to_tal_hdr(ctx)); if (unlikely(get_destroying_bit(t->parent_child))) return NULL; + /* Unlink and mark destroying before notifying the parent: + * a notifier which (recursively) calls tal_free() on ctx + * is then a no-op rather than unbounded recursion. */ + list_del(&t->list); + set_destroying_bit(&t->parent_child); if (notifiers) notify(ignore_destroying_bit(t->parent_child)->parent, TAL_NOTIFY_DEL_CHILD, ctx, saved_errno); - list_del(&t->list); - del_tree(t, ctx, saved_errno); + /* A notifier can rescue ctx by tal_steal()ing it elsewhere: + * add_child() clears the destroying bit. */ + if (!get_destroying_bit(t->parent_child)) { + errno = saved_errno; + return NULL; + } + del_tree_inner(t, ctx, saved_errno); errno = saved_errno; } return NULL; @@ -543,11 +570,28 @@ void *tal_steal_(const tal_t *new_parent, const tal_t *ctx) newpar = debug_tal(to_tal_hdr_or_null(new_parent)); t = debug_tal(to_tal_hdr(ctx)); - /* Unlink it from old parent. */ - list_del(&t->list); + /* Can't steal into a parent which is being destroyed: + * we'd be linked into the list del_tree() is draining, + * and freed (or looped on) anyway. */ + if (unlikely(get_destroying_bit(newpar->parent_child))) + return NULL; + + /* Unlink it from old parent (an object being destroyed + * has already been unlinked: it can only be stolen as a + * rescue from its destructor/notifier). */ + if (!get_destroying_bit(t->parent_child)) + list_del(&t->list); old_parent = ignore_destroying_bit(t->parent_child)->parent; if (unlikely(!add_child(newpar, t))) { + /* No fallback for a rescue from a destructor: + * re-linking into the old parent would silently + * keep the object (its destructor saw NULL), and if + * the old parent is mid-del_tree it would re-enter + * the list being drained. Leave it unlinked and + * destroying; the free proceeds. */ + if (get_destroying_bit(t->parent_child)) + return NULL; /* We can always add to old parent, because it has a * children property already. */ if (!add_child(old_parent, t)) @@ -800,6 +844,12 @@ bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count) old_len = debug_tal(to_tal_hdr(*ctxp))->bytelen; + /* Check for multiplicative overflow */ + if (size && unlikely(count * size / size != count)) { + call_error("dup size overflow"); + goto out; + } + /* Check for additive overflow */ if (old_len + count * size < old_len) { call_error("dup size overflow"); @@ -810,7 +860,9 @@ bool tal_expand_(tal_t **ctxp, const void *src, size_t size, size_t count) assert(src < *ctxp || (char *)src >= (char *)(*ctxp) + old_len); - if (!tal_resize_(ctxp, size, old_len/size + count, false)) + /* Resize by raw length, so excess bytes are preserved and + * tal_count() grows by exactly count. */ + if (!tal_resize_(ctxp, 1, old_len + count * size, false)) goto out; memcpy((char *)*ctxp + old_len, src, count * size); diff --git a/ccan/ccan/tal/tal.h b/ccan/ccan/tal/tal.h index 347a5e8c801a..9363e2db1e6d 100644 --- a/ccan/ccan/tal/tal.h +++ b/ccan/ccan/tal/tal.h @@ -143,7 +143,16 @@ void *tal_free(const tal_t *p); * * This may need to perform an allocation, in which case it may fail; thus * it can return NULL, otherwise returns @ptr. If @ptr is NULL, this function does - * nothing. + * nothing. It also fails (returning NULL) if @ctx is currently being + * destroyed. + * + * A destructor or TAL_NOTIFY_FREE notifier may use this to rescue @ptr + * from destruction by moving it to a new parent; the free is then + * aborted. The rescue is only noticed once every notifier and + * destructor registered for this pass has run, so later ones still + * fire (and all of them fire again when the object is finally + * destroyed). If the rescue fails (allocation failure), the free + * proceeds. */ #if HAVE_STATEMENT_EXPR /* Weird macro avoids gcc's 'warning: value computed is not used'. */ @@ -174,7 +183,8 @@ void *tal_free(const tal_t *p); * * If @function has not been successfully added as a destructor, this returns * false. Note that if we're inside the destructor call itself, this will - * return false. + * return false, and the destructor remains registered: it is restored when + * the call returns, in case the object was rescued from destruction. */ #define tal_del_destructor(ptr, function) \ tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr))) @@ -206,7 +216,8 @@ void *tal_free(const tal_t *p); * * If @function has not been successfully added as a destructor, this returns * false. Note that if we're inside the destructor call itself, this will - * return false. + * return false, and the destructor remains registered: it is restored when + * the call returns, in case the object was rescued from destruction. */ #define tal_del_destructor(ptr, function) \ tal_del_destructor_((ptr), typesafe_cb(void, void *, (function), (ptr))) @@ -272,6 +283,17 @@ enum tal_notify_type { * not called when this context is tal_free()d: TAL_NOTIFY_FREE is * considered sufficient for that case. * + * For TAL_NOTIFY_ADD_CHILD, the callback must not tal_free() or + * tal_steal() the child: the allocating call will still return it to + * the caller, so this will crash or corrupt. + * + * For TAL_NOTIFY_DEL_CHILD, the child is already unlinked and marked + * destroying: calling tal_free() on it from the callback is a no-op, + * and tal_steal()ing it rescues it from destruction (aborting the + * free). + * + * In all cases, the callback must not tal_free() @ptr itself. + * * TAL_NOTIFY_ADD_NOTIFIER/TAL_NOTIFIER_DEL_NOTIFIER are called when a * notifier is added or removed (not for this notifier): @info is the * callback. This is also called for tal_add_destructor and diff --git a/ccan/ccan/tcon/tcon.h b/ccan/ccan/tcon/tcon.h index 35d83e199b8b..eae7c942637c 100644 --- a/ccan/ccan/tcon/tcon.h +++ b/ccan/ccan/tcon/tcon.h @@ -127,6 +127,10 @@ * * It evaluates to @x so you can chain it. * + * Note that a @expr of type void * silently passes against any + * canary (the comparison is legal C); the same applies to + * tcon_check_ptr(). + * * Example: * #define tlist_add(h, n, member) \ * list_add(&tcon_check((h), canary, (n))->raw, &(n)->member) diff --git a/ccan/ccan/time/time.c b/ccan/ccan/time/time.c index 9810792280c7..85eb593102f8 100644 --- a/ccan/ccan/time/time.c +++ b/ccan/ccan/time/time.c @@ -2,6 +2,17 @@ #include #include #include +#include + +/* Largest representable tv_sec (time_t is signed). */ +#define TIMEREL_SEC_MAX \ + ((time_t)((~(uint64_t)0) >> (64 - sizeof(time_t)*CHAR_BIT + 1))) + +static struct timerel timerel_max(void) +{ + struct timerel max = { { TIMEREL_SEC_MAX, 999999999 } }; + return max; +} #if !HAVE_CLOCK_GETTIME #include @@ -58,6 +69,11 @@ struct timerel time_divide(struct timerel t, unsigned long div) /* FIXME: fp is cheating! */ double nsec = rem * 1000000000.0 + t.ts.tv_nsec; res.ts.tv_nsec = nsec / div; + /* Rounding can give exactly 1e9; renormalize. */ + if (res.ts.tv_nsec >= 1000000000) { + res.ts.tv_nsec -= 1000000000; + res.ts.tv_sec++; + } } else { ns = rem * 1000000000 + t.ts.tv_nsec; res.ts.tv_nsec = ns / div; @@ -69,11 +85,16 @@ struct timerel time_multiply(struct timerel t, unsigned long mult) { struct timerel res; + (void)TIMEREL_CHECK(t); + /* Are we going to overflow if we multiply nsec? */ if (mult & ~((1UL << 30) - 1)) { /* FIXME: fp is cheating! */ double nsec = (double)t.ts.tv_nsec * mult; + /* Saturate rather than overflow time_t. */ + if (nsec >= (double)TIMEREL_SEC_MAX * 1000000000.0) + return timerel_max(); res.ts.tv_sec = nsec / 1000000000.0; res.ts.tv_nsec = nsec - (res.ts.tv_sec * 1000000000.0); } else { @@ -82,7 +103,12 @@ struct timerel time_multiply(struct timerel t, unsigned long mult) res.ts.tv_nsec = nsec % 1000000000; res.ts.tv_sec = nsec / 1000000000; } - res.ts.tv_sec += TIMEREL_CHECK(t).ts.tv_sec * mult; + + /* The seconds multiply can overflow too: saturate. */ + if (mult != 0 + && t.ts.tv_sec > (time_t)((TIMEREL_SEC_MAX - res.ts.tv_sec) / mult)) + return timerel_max(); + res.ts.tv_sec += t.ts.tv_sec * mult; return TIMEREL_CHECK(res); } diff --git a/ccan/ccan/time/time.h b/ccan/ccan/time/time.h index cbfeefa055c0..d327e92d80b4 100644 --- a/ccan/ccan/time/time.h +++ b/ccan/ccan/time/time.h @@ -569,6 +569,9 @@ struct timerel time_divide(struct timerel t, unsigned long div); * @t: a relative time. * @mult: number to multiply it by. * + * If the result would not fit in a timerel, the maximum representable + * time is returned. + * * Example: * ... * printf("Time to do 100000 forks would be %u sec\n", diff --git a/ccan/ccan/timer/timer.c b/ccan/ccan/timer/timer.c index ef6b27742679..20263ad80cc1 100644 --- a/ccan/ccan/timer/timer.c +++ b/ccan/ccan/timer/timer.c @@ -153,6 +153,15 @@ static void timers_far_get(struct timers *timers, } } +/* Maximum time covered by levels 0..@level (from base); saturates + * once the range exceeds the representable 64 bits. */ +static uint64_t level_max_time(const struct timers *timers, unsigned int level) +{ + if ((level + 1) * TIMER_LEVEL_BITS >= 64) + return -1ULL; + return timers->base + (1ULL << ((level+1)*TIMER_LEVEL_BITS)) - 1; +} + static void add_level(struct timers *timers, unsigned int level) { struct timer_level *l; @@ -169,8 +178,7 @@ static void add_level(struct timers *timers, unsigned int level) timers->level[level] = l; list_head_init(&from_far); - timers_far_get(timers, &from_far, - timers->base + (1ULL << ((level+1)*TIMER_LEVEL_BITS)) - 1); + timers_far_get(timers, &from_far, level_max_time(timers, level)); while ((t = list_pop(&from_far, struct timer, list)) != NULL) timer_add_raw(timers, t); @@ -313,8 +321,7 @@ static void timer_fast_forward(struct timers *timers, uint64_t time) if (!timers->level[level]) { /* We need any which belong on this level. */ timers_far_get(timers, &list, - timers->base - + (1ULL << ((level+1)*TIMER_LEVEL_BITS))-1); + level_max_time(timers, level)); need_level = level; } else { unsigned src; @@ -353,6 +360,9 @@ struct timer *timers_expire(struct timers *timers, struct timemono expire) if (list_empty(&timers->far)) return NULL; add_level(timers, 0); + /* Allocation failure: timers wait safely on the far list. */ + if (!timers->level[0]) + return NULL; } do { @@ -448,8 +458,13 @@ struct timers *timers_check(const struct timers *timers, const char *abortstr) } past_levels: - base = (timers->base & ~((1ULL << (TIMER_LEVEL_BITS * l)) - 1)) - + (1ULL << (TIMER_LEVEL_BITS * l)) - 1; + if (TIMER_LEVEL_BITS * l < 64) { + base = (timers->base & ~((1ULL << (TIMER_LEVEL_BITS * l)) - 1)) + + (1ULL << (TIMER_LEVEL_BITS * l)) - 1; + } else { + /* Levels cover all representable times: far must be empty. */ + base = -1ULL; + } if (!timer_list_check(&timers->far, base, -1ULL, timers->firsts[ARRAY_SIZE(timers->level)], abortstr)) diff --git a/ccan/ccan/typesafe_cb/test/compile_fail-typesafe_cb-int.c b/ccan/ccan/typesafe_cb/test/compile_fail-typesafe_cb-int.c index c9d47c50b17f..ed3230d8a212 100644 --- a/ccan/ccan/typesafe_cb/test/compile_fail-typesafe_cb-int.c +++ b/ccan/ccan/typesafe_cb/test/compile_fail-typesafe_cb-int.c @@ -10,7 +10,7 @@ void _callback(void (*fn)(void *arg), void *arg) /* Callback is set up to warn if arg isn't a pointer (since it won't * pass cleanly to _callback's second arg. */ #define callback(fn, arg) \ - _callback(typesafe_cb(void, (fn), (arg)), (arg)) + _callback(typesafe_cb(void, void *, (fn), (arg)), (arg)) void my_callback(int something); void my_callback(int something) @@ -23,6 +23,9 @@ int main(void) #ifdef FAIL /* This fails due to arg, not due to cast. */ callback(my_callback, 100); +#if !HAVE_TYPEOF||!HAVE_BUILTIN_CHOOSE_EXPR||!HAVE_BUILTIN_TYPES_COMPATIBLE_P +#error "Unfortunately we don't fail if typesafe_cb is a noop." +#endif #endif return 0; } diff --git a/ccan/ccan/typesafe_cb/typesafe_cb.h b/ccan/ccan/typesafe_cb/typesafe_cb.h index 126d325c7821..9bc76542b14f 100644 --- a/ccan/ccan/typesafe_cb/typesafe_cb.h +++ b/ccan/ccan/typesafe_cb/typesafe_cb.h @@ -78,6 +78,11 @@ * It is assumed that @arg is of pointer type: usually @arg is passed * or assigned to a void * elsewhere anyway. * + * Note that the callback must have a prototype: an unprototyped + * function (ie. "void fn()") defeats this check entirely, and is + * silently accepted with any @arg type (gcc and clang give no + * diagnostic at -Wall). + * * Example: * void _register_callback(void (*fn)(void *arg), void *arg); * #define register_callback(fn, arg) \ diff --git a/ccan/tools/configurator/configurator.c b/ccan/tools/configurator/configurator.c index 085034fd0eec..7beecd494ebe 100644 --- a/ccan/tools/configurator/configurator.c +++ b/ccan/tools/configurator/configurator.c @@ -396,6 +396,9 @@ static const struct test base_tests[] = { { "HAVE_STATEMENT_EXPR", "statement expression support", "INSIDE_MAIN", NULL, NULL, "return ({ int x = argc; x == argc ? 0 : 1; });" }, + { "HAVE_STATIC_ASSERT", "_Static_assert support", + "INSIDE_MAIN", NULL, NULL, + "_Static_assert(1, \"OK\"); return 0;" }, { "HAVE_SYS_FILIO_H", "", "OUTSIDE_MAIN", NULL, NULL, /* Solaris needs this for FIONREAD */ "#include \n" },