diff --git a/Makefile b/Makefile index 3e74d4bc7..8a6ff9e54 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,7 @@ LDLIBS = -L/usr/local/lib -lm -lgmp -lsqlite3 -lz $(COVFLAGS) default: all-programs all-test-programs -config.vars ccan/config.h: configure +config.vars ccan/config.h: configure ccan/tools/configurator/configurator.c @if [ ! -f config.vars ]; then echo 'The 1990s are calling: use ./configure!' >&2; exit 1; fi ./configure --reconfigure diff --git a/ccan/README b/ccan/README index de2927b94..e08a994a9 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2454-gc656dceb +CCAN version: init-2455-gd3d2242b diff --git a/ccan/ccan/compiler/compiler.h b/ccan/ccan/compiler/compiler.h index bce4f25a1..caa89edc5 100644 --- a/ccan/ccan/compiler/compiler.h +++ b/ccan/ccan/compiler/compiler.h @@ -228,4 +228,62 @@ #define WARN_UNUSED_RESULT #endif #endif + + +#if HAVE_ATTRIBUTE_DEPRECATED +/** + * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used. + * + * Used to mark a function, type or variable should not be used. + * + * Example: + * WARN_DEPRECATED char *oldfunc(char *buf); + */ +#define WARN_DEPRECATED __attribute__((__deprecated__)) +#else +#define WARN_DEPRECATED +#endif + + +#if HAVE_ATTRIBUTE_NONNULL +/** + * NO_NULL_ARGS - specify that no arguments to this function can be NULL. + * + * The compiler will warn if any pointer args are NULL. + * + * Example: + * NO_NULL_ARGS char *my_copy(char *buf); + */ +#define NO_NULL_ARGS __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. + * + * The compiler will warn if any of the specified pointer args are NULL. + * + * Example: + * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1, 2); + */ +#define NON_NULL_ARGS(index, ...) __attribute__((__nonnull__(index, __VA_ARGS__))) +#else +#define NO_NULL_ARGS +#define NON_NULL_ARGS(index, ...) +#endif + + +#if HAVE_ATTRIBUTE_SENTINEL +/** + * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL. + * + * The compiler will warn if the last argument isn't NULL. + * + * Example: + * char *join_string(char *buf, ...) LAST_ARG_NULL; + */ +#define LAST_ARG_NULL __attribute__((__sentinel__)) +#else +#define LAST_ARG_NULL +#endif + #endif /* CCAN_COMPILER_H */ diff --git a/ccan/ccan/pipecmd/_info b/ccan/ccan/pipecmd/_info index a560bfea0..8c49511a2 100644 --- a/ccan/ccan/pipecmd/_info +++ b/ccan/ccan/pipecmd/_info @@ -32,7 +32,7 @@ * exit(1); * exit(0); * } - * child = pipecmd(&outputfd, NULL, NULL, argv[0], "ignoredarg", NULL); + * child = pipecmd(NULL, &outputfd, NULL, argv[0], "ignoredarg", NULL); * if (child < 0) * err(1, "Creating child"); * if (read(outputfd, input, sizeof(input)) != sizeof(input)) diff --git a/ccan/ccan/pipecmd/pipecmd.c b/ccan/ccan/pipecmd/pipecmd.c index 32772a83b..c2b514df5 100644 --- a/ccan/ccan/pipecmd/pipecmd.c +++ b/ccan/ccan/pipecmd/pipecmd.c @@ -6,6 +6,8 @@ #include #include +int pipecmd_preserve; + static char **gather_args(const char *arg0, va_list ap) { size_t n = 1; @@ -26,7 +28,7 @@ static char **gather_args(const char *arg0, va_list ap) return arr; } -pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, +pid_t pipecmdv(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, const char *cmd, va_list ap) { char **arr = gather_args(cmd, ap); @@ -36,12 +38,12 @@ pid_t pipecmdv(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, errno = ENOMEM; return -1; } - ret = pipecmdarr(fd_fromchild, fd_tochild, fd_errfromchild, arr); + ret = pipecmdarr(fd_tochild, fd_fromchild, fd_errfromchild, arr); free_noerr(arr); return ret; } -pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, +pid_t pipecmdarr(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, char *const *arr) { int tochild[2], fromchild[2], errfromchild[2], execfail[2]; @@ -49,7 +51,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, int err; if (fd_tochild) { - if (pipe(tochild) != 0) + if (fd_tochild == &pipecmd_preserve) { + tochild[0] = STDIN_FILENO; + fd_tochild = NULL; + } else if (pipe(tochild) != 0) goto fail; } else { tochild[0] = open("/dev/null", O_RDONLY); @@ -57,7 +62,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, goto fail; } if (fd_fromchild) { - if (pipe(fromchild) != 0) + if (fd_fromchild == &pipecmd_preserve) { + fromchild[1] = STDOUT_FILENO; + fd_fromchild = NULL; + } else if (pipe(fromchild) != 0) goto close_tochild_fail; } else { fromchild[1] = open("/dev/null", O_WRONLY); @@ -65,7 +73,10 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, goto close_tochild_fail; } if (fd_errfromchild) { - if (fd_errfromchild == fd_fromchild) { + if (fd_errfromchild == &pipecmd_preserve) { + errfromchild[1] = STDERR_FILENO; + fd_errfromchild = NULL; + } else if (fd_errfromchild == fd_fromchild) { errfromchild[0] = fromchild[0]; errfromchild[1] = fromchild[1]; } else { @@ -77,7 +88,7 @@ pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, if (errfromchild[1] < 0) goto close_fromchild_fail; } - + if (pipe(execfail) != 0) goto close_errfromchild_fail; @@ -168,14 +179,14 @@ fail: return -1; } -pid_t pipecmd(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, +pid_t pipecmd(int *fd_tochild, int *fd_fromchild, int *fd_errfromchild, const char *cmd, ...) { pid_t childpid; va_list ap; va_start(ap, cmd); - childpid = pipecmdv(fd_fromchild, fd_tochild, fd_errfromchild, cmd, ap); + childpid = pipecmdv(fd_tochild, fd_fromchild, fd_errfromchild, cmd, ap); va_end(ap); return childpid; diff --git a/ccan/ccan/pipecmd/pipecmd.h b/ccan/ccan/pipecmd/pipecmd.h index 481695050..5bbaefc01 100644 --- a/ccan/ccan/pipecmd/pipecmd.h +++ b/ccan/ccan/pipecmd/pipecmd.h @@ -18,6 +18,7 @@ * If @errfd is NULL, the child's stderr is (write-only) /dev/null. * * If @errfd == @outfd (and non-NULL) they will be shared. + * If @infd, @outfd or @errfd is &pipecmd_preserve, it is unchanged. * * The return value is the pid of the child, or -1. */ @@ -41,4 +42,10 @@ pid_t pipecmdv(int *infd, int *outfd, int *errfd, const char *cmd, va_list ap); * @arr: NULL-terminated array for arguments (first is program to run). */ pid_t pipecmdarr(int *infd, int *outfd, int *errfd, char *const *arr); + +/** + * pipecmd_preserve - special value for fds to indicate it is unchanged + */ +extern int pipecmd_preserve; + #endif /* CCAN_PIPECMD_H */ diff --git a/ccan/ccan/pipecmd/test/run-fdleak.c b/ccan/ccan/pipecmd/test/run-fdleak.c index 775ef333f..6b7729060 100644 --- a/ccan/ccan/pipecmd/test/run-fdleak.c +++ b/ccan/ccan/pipecmd/test/run-fdleak.c @@ -21,7 +21,7 @@ int main(int argc, char *argv[]) /* This is how many tests you plan to run */ plan_tests(13); - child = pipecmd(&outfd, NULL, NULL, argv[0], "out", NULL); + child = pipecmd(NULL, &outfd, NULL, argv[0], "out", NULL); if (!ok1(child > 0)) exit(1); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); diff --git a/ccan/ccan/pipecmd/test/run.c b/ccan/ccan/pipecmd/test/run.c index 45b96ab2f..e446da6d1 100644 --- a/ccan/ccan/pipecmd/test/run.c +++ b/ccan/ccan/pipecmd/test/run.c @@ -48,7 +48,7 @@ int main(int argc, char *argv[]) /* This is how many tests you plan to run */ plan_tests(67); - child = pipecmd(&outfd, &infd, &errfd, argv[0], "inout", NULL); + child = pipecmd(&infd, &outfd, &errfd, argv[0], "inout", NULL); if (!ok1(child > 0)) exit(1); ok1(write(infd, buf, sizeof(buf)) == sizeof(buf)); @@ -63,7 +63,7 @@ int main(int argc, char *argv[]) ok1(WIFEXITED(status)); ok1(WEXITSTATUS(status) == 0); - child = pipecmd(NULL, &infd, NULL, argv[0], "in", NULL); + child = pipecmd(&infd, NULL, NULL, argv[0], "in", NULL); if (!ok1(child > 0)) exit(1); ok1(write(infd, buf, sizeof(buf)) == sizeof(buf)); @@ -72,7 +72,7 @@ int main(int argc, char *argv[]) ok1(WIFEXITED(status)); ok1(WEXITSTATUS(status) == 0); - child = pipecmd(&outfd, NULL, NULL, argv[0], "out", NULL); + child = pipecmd(NULL, &outfd, NULL, argv[0], "out", NULL); if (!ok1(child > 0)) exit(1); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); @@ -94,7 +94,7 @@ int main(int argc, char *argv[]) ok1(WEXITSTATUS(status) == 0); /* errfd == outfd should work with both. */ - child = pipecmd(&errfd, NULL, &errfd, argv[0], "err", NULL); + child = pipecmd(NULL, &errfd, &errfd, argv[0], "err", NULL); if (!ok1(child > 0)) exit(1); ok1(read(errfd, buf, sizeof(buf)) == sizeof(buf)); @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) ok1(WIFEXITED(status)); ok1(WEXITSTATUS(status) == 0); - child = pipecmd(&outfd, NULL, &outfd, argv[0], "out", NULL); + child = pipecmd(NULL, &outfd, &outfd, argv[0], "out", NULL); if (!ok1(child > 0)) exit(1); ok1(read(outfd, buf, sizeof(buf)) == sizeof(buf)); diff --git a/ccan/ccan/take/take.c b/ccan/ccan/take/take.c index c628aac0d..4833bf935 100644 --- a/ccan/ccan/take/take.c +++ b/ccan/ccan/take/take.c @@ -32,9 +32,20 @@ void *take_(const void *p, const char *label) } takenarr = new; /* Once labelarr is set, we maintain it. */ - if (labelarr) - labelarr = realloc(labelarr, - sizeof(*labelarr) * (max_taken+1)); + if (labelarr) { + const char **labelarr_new; + labelarr_new = realloc(labelarr, + sizeof(*labelarr) * (max_taken+1)); + if (labelarr_new) { + labelarr = labelarr_new; + } else { + /* num_taken will be out of sync with the size of + * labelarr after realloc failure. + * Just pretend that we never had labelarr allocated. */ + free(labelarr); + labelarr = NULL; + } + } max_taken++; } if (unlikely(labelarr)) diff --git a/ccan/tools/configurator/configurator.c b/ccan/tools/configurator/configurator.c index 239e91c96..1386fc90c 100644 --- a/ccan/tools/configurator/configurator.c +++ b/ccan/tools/configurator/configurator.c @@ -136,6 +136,15 @@ static const struct test base_tests[] = { { "HAVE_ATTRIBUTE_CONST", "__attribute__((const)) support", "DEFINES_FUNC", NULL, NULL, "static int __attribute__((const)) func(int x) { return x; }" }, + { "HAVE_ATTRIBUTE_DEPRECATED", "__attribute__((deprecated)) support", + "DEFINES_FUNC", NULL, NULL, + "static int __attribute__((deprecated)) func(int x) { return x; }" }, + { "HAVE_ATTRIBUTE_NONNULL", "__attribute__((nonnull)) support", + "DEFINES_FUNC", NULL, NULL, + "static char *__attribute__((nonnull)) func(char *p) { return p; }" }, + { "HAVE_ATTRIBUTE_SENTINEL", "__attribute__((sentinel)) support", + "DEFINES_FUNC", NULL, NULL, + "static int __attribute__((sentinel)) func(int i, ...) { return i; }" }, { "HAVE_ATTRIBUTE_PURE", "__attribute__((pure)) support", "DEFINES_FUNC", NULL, NULL, "static int __attribute__((pure)) func(int x) { return x; }" }, diff --git a/lightningd/bitcoind.c b/lightningd/bitcoind.c index 55b261d2d..918e891d2 100644 --- a/lightningd/bitcoind.c +++ b/lightningd/bitcoind.c @@ -229,7 +229,7 @@ static void next_bcli(struct bitcoind *bitcoind, enum bitcoind_prio prio) if (!bcli) return; - bcli->pid = pipecmdarr(&bcli->fd, NULL, &bcli->fd, + bcli->pid = pipecmdarr(NULL, &bcli->fd, &bcli->fd, cast_const2(char **, bcli->args)); if (bcli->pid < 0) fatal("%s exec failed: %s", bcli->args[0], strerror(errno)); @@ -806,7 +806,7 @@ void wait_for_bitcoind(struct bitcoind *bitcoind) bool printed = false; for (;;) { - child = pipecmdarr(&from, NULL, &from, cast_const2(char **,cmd)); + child = pipecmdarr(NULL, &from, &from, cast_const2(char **,cmd)); if (child < 0) { if (errno == ENOENT) { fatal_bitcoind_failure(bitcoind, "bitcoin-cli not found. Is bitcoin-cli (part of Bitcoin Core) available in your PATH?"); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 1b897211a..3708fa223 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -258,10 +258,10 @@ void test_subdaemons(const struct lightningd *ld) const char *dpath = path_join(tmpctx, ld->daemon_dir, subdaemons[i]); const char *verstring; /*~ CCAN's pipecmd module is like popen for grownups: it - * takes pointers to fill in stdout, stdin and stderr file + * takes pointers to fill in stdin, stdout and stderr file * descriptors if desired, and the remainder of arguments * are the command and its argument. */ - pid_t pid = pipecmd(&outfd, NULL, &outfd, + pid_t pid = pipecmd(NULL, &outfd, &outfd, dpath, "--version", NULL); /*~ Our logging system: spam goes in at log_debug level, but diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 46d72dc6b..72457a46f 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -785,7 +785,7 @@ void plugins_init(struct plugins *plugins, const char *dev_plugin_debug) cmd[0] = p->cmd; if (debug) cmd[1] = "--debugger"; - p->pid = pipecmdarr(&stdout, &stdin, NULL, cmd); + p->pid = pipecmdarr(&stdin, &stdout, NULL, cmd); if (p->pid == -1) fatal("error starting plugin '%s': %s", p->cmd,