Commit 2621f3ad authored by Rusty Russell's avatar Rusty Russell

ccanlint: objects_build_with_stringchecks

If we detect any mention of a problematic string function, try compiling
the entire module with string debugging enabled.
parent ecea0736
#include <tools/ccanlint/ccanlint.h>
#include <tools/tools.h>
#include <ccan/talloc/talloc.h>
#include <ccan/str/str.h>
#include <ccan/str_talloc/str_talloc.h>
#include <ccan/foreach/foreach.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <err.h>
#include <string.h>
#include <ctype.h>
#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 <ccan/str/str.h>\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 <ccan/%s/%s.h>\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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment