|
|
@@ -0,0 +1,145 @@
|
|
|
+#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);
|