From: Rusty Russell Date: Thu, 17 Mar 2011 11:42:22 +0000 (+1030) Subject: ccanlint: objects_build_with_stringchecks X-Git-Url: https://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=2621f3adc8786e6655c69edc29d6a3560d41cd32 ccanlint: objects_build_with_stringchecks If we detect any mention of a problematic string function, try compiling the entire module with string debugging enabled. --- diff --git a/tools/ccanlint/tests/objects_build_with_stringchecks.c b/tools/ccanlint/tests/objects_build_with_stringchecks.c new file mode 100644 index 00000000..32fa22ea --- /dev/null +++ b/tools/ccanlint/tests/objects_build_with_stringchecks.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "reduce_features.h" + +static const char *uses_stringfuncs(struct manifest *m) +{ + struct list_head *list; + + foreach_ptr(list, &m->c_files, &m->h_files) { + struct ccan_file *i; + char *match; + + list_for_each(list, i, list) { + if (strreg(m, get_ccan_file_contents(i), + "(isalnum|isalpha|isascii|isblank|iscntrl" + "|isdigit|isgraph|islower|isprint|ispunct" + "|isspace|isupper|isxdigit" + "|strstr|strchr|strrchr)", &match)) { + if (verbose > 2) + printf("Matched '%s' in %s\n", + match, i->fullname); + return NULL; + } + } + } + return "No ctype.h or string functions found"; +} + +static void write_str(int fd, const char *str) +{ + if (write(fd, str, strlen(str)) != strlen(str)) + err(1, "Writing to temporary file"); +} + +static int start_file(const char *filename) +{ + int fd; + fd = open(filename, O_WRONLY|O_CREAT, 0600); + write_str(fd, "#define CCAN_STR_DEBUG 1\n#include \n"); + return fd; +} + +static void test_compile(struct score *score, + struct ccan_file *file, + const char *filename, + bool keep, + const char *flags, + bool *errors, + bool *warnings) +{ + char *output, *compiled; + + compiled = maybe_temp_file(score, "", keep, filename); + if (!compile_object(score, filename, ccan_dir, compiler, flags, + compiled, &output)) { + score_file_error(score, file, 0, + "Compiling object files:\n%s", + output); + *errors = true; + } else if (!streq(output, "")) { + score_file_error(score, file, 0, + "Compiling object files gave warnings:\n%s", + output); + *warnings = true; + } +} + +static struct ccan_file *get_main_header(struct manifest *m) +{ + struct ccan_file *f; + + list_for_each(&m->h_files, f, list) { + if (strstarts(f->name, m->basename) + && strlen(f->name) == strlen(m->basename) + 2) { + return f; + } + } + /* Should not happen, since we passed main_header_exists! */ + errx(1, "No main header?"); +} + +static void build_objects_with_stringchecks(struct manifest *m, + bool keep, unsigned int *timeleft, + struct score *score) +{ + struct ccan_file *i; + bool errors = false, warnings = false; + char *tmp, *flags; + int tmpfd; + + /* FIXME:: We need -I so local #includes work outside normal dir. */ + flags = talloc_asprintf(score, "-I%s %s", m->dir, cflags); + + /* Won't work into macros, but will get inline functions. */ + if (list_empty(&m->c_files)) { + char *line; + i = get_main_header(m); + tmp = maybe_temp_file(score, ".c", keep, i->fullname); + tmpfd = start_file(tmp); + line = talloc_asprintf(score, "#include \n", + m->basename, m->basename); + write_str(tmpfd, line); + close(tmpfd); + test_compile(score, i, tmp, keep, flags, &errors, &warnings); + } else { + list_for_each(&m->c_files, i, list) { + tmp = maybe_temp_file(score, ".c", keep, i->fullname); + tmpfd = start_file(tmp); + write_str(tmpfd, get_ccan_file_contents(i)); + close(tmpfd); + test_compile(score, i, tmp, keep, flags, + &errors, &warnings); + } + } + + score->total = 1; + if (!errors) { + score->pass = true; + score->score = !warnings; + } +} + +struct ccanlint objects_build_with_stringchecks = { + .key = "objects_build_with_stringchecks", + .name = "Module compiles with extra ctype.h and str function checks", + .check = build_objects_with_stringchecks, + .can_run = uses_stringfuncs, + .needs = "objects_build main_header_exists" +}; +REGISTER_TEST(objects_build_with_stringchecks);