Print this page
Incorporate rmustacc's review feedback.

@@ -8,18 +8,16 @@
  * source.  A copy of the CDDL is also available via the Internet at
  * http://www.illumos.org/license/CDDL.
  */
 
 /*
- * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2015 Garrett D'Amore <garrett@damore.org>
  */
 
 /*
  * This program tests symbol visibility using the /usr/bin/c89 and
  * /usr/bin/c99 programs.
- *
- * See symbols_defs.c for the actual list of symbols tested.
  */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

@@ -34,10 +32,11 @@
 
 char *dname;
 char *cfile;
 char *ofile;
 char *lfile;
+char *efile;
 
 const char *sym = NULL;
 
 static int good_count = 0;
 static int fail_count = 0;

@@ -60,29 +59,15 @@
         "/opt/sfw/bin/gcc",
         "/usr/local/bin/gcc",
         NULL
 };
 
-const char *puname[] = {
-        "",
-        "/usr/bin/puname -S "
-};
-
 char *compiler = NULL;
 const char *c89flags = NULL;
 const char *c99flags = NULL;
 
-/* ====== BEGIN ======== */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <stdint.h>
-
-#define MAXENV  64      /* bits */
+#define MAXENV  64      /* maximum number of environments (bitmask width) */
 #define MAXHDR  10      /* maximum # headers to require to access symbol */
 #define MAXARG  20      /* maximum # of arguments */
 
 #define WS      " \t"
 

@@ -120,11 +105,47 @@
 struct env_group *env_groups = NULL;
 
 struct sym_test *sym_tests = NULL;
 struct sym_test **sym_insert = &sym_tests;
 
+static char *
+mystrdup(const char *s)
+{
+        char *r;
+        if ((r = strdup(s)) == NULL) {
+                perror("strdup");
+                exit(1);
+        }
+        return (r);
+}
+
+static void *
+myzalloc(size_t sz)
+{
+        void *buf; 
+        if ((buf = calloc(1, sz)) == NULL) {
+                perror("calloc");
+                exit(1);
+        }
+        return (buf);
+}
+
 static void
+myasprintf(char **buf, const char *fmt, ...)
+{
+        int rv;
+        va_list va;
+        va_start(va, fmt);
+        rv = vasprintf(buf, fmt, va);
+        va_end(va);
+        if (rv < 0) {
+                perror("vasprintf");
+                exit(1);
+        }
+}
+
+static void
 append_sym_test(struct sym_test *st)
 {
         *sym_insert = st;
         sym_insert = &st->next;
 }

@@ -209,26 +230,26 @@
         char *name;
         char *lang;
         char *defs;
 
         if (nfields != 3) {
-                (void) asprintf(err, "number of fields (%d) != 3", nfields);
+                myasprintf(err, "number of fields (%d) != 3", nfields);
                 return (-1);
         }
 
         if (next_env >= MAXENV) {
-                (void) asprintf(err, "too many environments");
+                myasprintf(err, "too many environments");
                 return (-1);
         }
 
         name = fields[0];
         lang = fields[1];
         defs = fields[2];
 
-        compile_env[next_env].name = strdup(name);
-        compile_env[next_env].lang = strdup(lang);
-        compile_env[next_env].defs = strdup(defs);
+        compile_env[next_env].name = mystrdup(name);
+        compile_env[next_env].lang = mystrdup(lang);
+        compile_env[next_env].defs = mystrdup(defs);
         compile_env[next_env].index = next_env;
         next_env++;
         return (0);
 }
 

@@ -240,144 +261,178 @@
         struct env_group *eg;
         uint64_t mask;
         char *item;
 
         if (nfields != 2) {
-                (void) asprintf(err, "number of fields (%d) != 2", nfields);
+                myasprintf(err, "number of fields (%d) != 2", nfields);
                 return (-1);
         }
 
         name = fields[0];
         list = fields[1];
         mask = 0;
 
         if (expand_env(list, &mask, &item) < 0) {
-                (void) asprintf(err, "reference to undefined env %s", item);
+                myasprintf(err, "reference to undefined env %s", item);
                 return (-1);
         }
 
-        eg = calloc(1, sizeof (*eg));
-        eg->name = strdup(name);
+        eg = myzalloc(sizeof (*eg));
+        eg->name = mystrdup(name);
         eg->mask = mask;
         eg->next = env_groups;
         env_groups = eg;
         return (0);
 }
 
+static char *progbuf = NULL;
+size_t proglen = 0;
+size_t progsiz = 0;
+
 static void
+addprogch(char c)
+{
+        while (progsiz <= (proglen + 1)) {
+                progbuf = realloc(progbuf, progsiz + 4096);
+                if (progbuf == NULL) {
+                        perror("realloc");
+                        exit(1);
+                }
+                progsiz += 1024;
+        }
+        progbuf[proglen++] = c;
+        progbuf[proglen] = 0;
+}
+
+static void
+addprogstr(char *s)
+{
+        while (*s != NULL) {
+                addprogch(*s);
+                s++;
+        }
+}
+
+static void
+addprogfmt(const char *fmt, ...)
+{
+        va_list va;
+        char *buf = NULL;
+        va_start(va, fmt);
+        if (vasprintf(&buf, fmt, va) < 0) {
+                perror("vasprintf");
+                exit(1);
+        }
+        va_end(va);
+        addprogstr(buf);
+        free(buf);
+}
+
+static void
 mkprog(struct sym_test *st)
 {
-        static char buf[2048];
         char *s;
-        char *prog = buf;
 
-        *prog = 0;
+        proglen = 0;
 
-#define ADDSTR(p, str)  (void) strcpy(p, str); p += strlen(p)
-#define ADDFMT(p, ...)  \
-        (void) snprintf(p, sizeof (buf) - (p-buf), __VA_ARGS__); \
-        p += strlen(p)
-#define ADDCHR(p, c)    *p++ = c; *p = 0
-
         for (int i = 0; i < MAXHDR && st->hdrs[i] != NULL; i++) {
-                ADDFMT(prog, "#include <%s>\n", st->hdrs[i]);
+                addprogfmt("#include <%s>\n", st->hdrs[i]);
         }
 
         for (s = st->rtype; *s; s++) {
-                ADDCHR(prog, *s);
+                addprogch(*s);
                 if (*s == '(') {
                         s++;
-                        ADDCHR(prog, *s);
+                        addprogch(*s);
                         s++;
                         break;
                 }
         }
-        ADDCHR(prog, ' ');
+        addprogch(' ');
 
         /* for function pointers, s is closing suffix, otherwise empty */
 
         switch (st->type) {
         case SYM_TYPE:
-                ADDFMT(prog, "test_type;", st->rtype);
+                addprogstr("test_type;");
                 break;
 
         case SYM_VALUE:
-                ADDFMT(prog, "test_value%s;\n", s);     /* s usually empty */
-                ADDSTR(prog, "void\ntest_func(void)\n{\n");
-                ADDFMT(prog, "\ttest_value = %s;\n}",
-                    st->name);
+                addprogfmt("test_value%s;\n", s);       /* s usually empty */
+                addprogstr("void\ntest_func(void)\n{\n");
+                addprogfmt("\ttest_value = %s;\n}", st->name);
                 break;
 
         case SYM_FUNC:
-                ADDSTR(prog, "\ntest_func(");
+                addprogstr("\ntest_func(");
                 for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) {
                         int didname = 0;
                         if (i > 0) {
-                                ADDSTR(prog, ", ");
+                                addprogstr(", ");
                         }
                         if (strcmp(st->atypes[i], "void") == 0) {
                                 didname = 1;
                         }
                         if (strcmp(st->atypes[i], "") == 0) {
                                 didname = 1;
-                                ADDSTR(prog, "void");
+                                addprogstr("void");
                         }
 
                         /* print the argument list */
                         for (char *a = st->atypes[i]; *a; a++) {
                                 if (*a == '(' && a[1] == '*' && !didname) {
-                                        ADDFMT(prog, "(*a%d", i);
+                                        addprogfmt("(*a%d", i);
                                         didname = 1;
                                         a++;
                                 } else if (*a == '[' && !didname) {
-                                        ADDFMT(prog, "a%d[", i);
+                                        addprogfmt("a%d[", i);
                                         didname = 1;
                                 } else {
-                                        ADDCHR(prog, *a);
+                                        addprogch(*a);
                                 }
                         }
                         if (!didname) {
-                                ADDFMT(prog, " a%d", i);
+                                addprogfmt(" a%d", i);
                         }
                 }
 
                 if (st->atypes[0] == NULL) {
-                        ADDSTR(prog, "void");
+                        addprogstr("void");
                 }
 
                 /* close argument list, and closing ")" for func ptrs */
-                ADDFMT(prog, ")%s\n{\n\t", s);  /* NB: s is normally empty */
+                addprogfmt(")%s\n{\n\t", s);    /* NB: s is normally empty */
 
                 if (strcmp(st->rtype, "") != 0 &&
                     strcmp(st->rtype, "void") != 0) {
-                        ADDSTR(prog, "return ");
+                        addprogstr("return ");
                 }
 
                 /* add the function call */
-                ADDFMT(prog, "%s(", st->name);
+                addprogfmt("%s(", st->name);
                 for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) {
                         if (strcmp(st->atypes[i], "") != 0 &&
                             strcmp(st->atypes[i], "void") != 0) {
-                                ADDFMT(prog, "%sa%d", i > 0 ? ", " : "", i);
+                                addprogfmt("%sa%d", i > 0 ? ", " : "", i);
                         }
                 }
 
-                ADDSTR(prog, ");\n}");
+                addprogstr(");\n}");
                 break;
         }
 
-        ADDCHR(prog, '\n');
+        addprogch('\n');
 
-        st->prog = strdup(buf);
+        st->prog = progbuf;
 }
 
 static int
 add_envs(struct sym_test *st, char *envs, char **err)
 {
         char *item;
         if (expand_env_list(envs, &st->test_mask, &st->need_mask, &item) < 0) {
-                (void) asprintf(err, "bad env action %s", item);
+                myasprintf(err, "bad env action %s", item);
                 return (-1);
         }
         return (0);
 }
 

@@ -386,15 +441,15 @@
 {
         int i = 0;
 
         for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) {
                 if (i >= MAXHDR) {
-                        (void) asprintf(err, "too many headers");
+                        myasprintf(err, "too many headers");
                         return (-1);
                 }
                 test_trim(&h);
-                st->hdrs[i++] = strdup(h);
+                st->hdrs[i++] = mystrdup(h);
         }
 
         return (0);
 }
 

@@ -403,15 +458,15 @@
 {
         int i = 0;
         char *a;
         for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) {
                 if (i >= MAXARG) {
-                        (void) asprintf(err, "too many arguments");
+                        myasprintf(err, "too many arguments");
                         return (-1);
                 }
                 test_trim(&a);
-                st->atypes[i++] = strdup(a);
+                st->atypes[i++] = mystrdup(a);
         }
 
         return (0);
 }
 

@@ -422,21 +477,21 @@
         char *hdrs;
         char *envs;
         struct sym_test *st;
 
         if (nfields != 3) {
-                (void) asprintf(err, "number of fields (%d) != 3", nfields);
+                myasprintf(err, "number of fields (%d) != 3", nfields);
                 return (-1);
         }
         decl = fields[0];
         hdrs = fields[1];
         envs = fields[2];
 
-        st = calloc(1, sizeof (*st));
+        st = myzalloc(sizeof (*st));
         st->type = SYM_TYPE;
-        st->name = strdup(decl);
-        st->rtype = strdup(decl);
+        st->name = mystrdup(decl);
+        st->rtype = mystrdup(decl);
 
         if ((add_envs(st, envs, err) < 0) ||
             (add_headers(st, hdrs, err) < 0)) {
                 return (-1);
         }

@@ -453,22 +508,22 @@
         char *hdrs;
         char *envs;
         struct sym_test *st;
 
         if (nfields != 4) {
-                (void) asprintf(err, "number of fields (%d) != 4", nfields);
+                myasprintf(err, "number of fields (%d) != 4", nfields);
                 return (-1);
         }
         name = fields[0];
         type = fields[1];
         hdrs = fields[2];
         envs = fields[3];
 
-        st = calloc(1, sizeof (*st));
+        st = myzalloc(sizeof (*st));
         st->type = SYM_VALUE;
-        st->name = strdup(name);
-        st->rtype = strdup(type);
+        st->name = mystrdup(name);
+        st->rtype = mystrdup(type);
 
         if ((add_envs(st, envs, err) < 0) ||
             (add_headers(st, hdrs, err) < 0)) {
                 return (-1);
         }

@@ -486,23 +541,23 @@
         char *hdrs;
         char *envs;
         struct sym_test *st;
 
         if (nfields != 5) {
-                (void) asprintf(err, "number of fields (%d) != 5", nfields);
+                myasprintf(err, "number of fields (%d) != 5", nfields);
                 return (-1);
         }
         name = fields[0];
         rtype = fields[1];
         atype = fields[2];
         hdrs = fields[3];
         envs = fields[4];
 
-        st = calloc(1, sizeof (*st));
+        st = myzalloc(sizeof (*st));
         st->type = SYM_FUNC;
-        st->name = strdup(name);
-        st->rtype = strdup(rtype);
+        st->name = mystrdup(name);
+        st->rtype = mystrdup(rtype);
 
         if ((add_envs(st, envs, err) < 0) ||
             (add_headers(st, hdrs, err) < 0) ||
             (add_arg_types(st, atype, err) < 0)) {
                 return (-1);

@@ -532,12 +587,13 @@
 {
         return (st->name);
 }
 
 /*
- * Iterate through tests.  Pass NULL for cenv first time, and previous result
- * the next.  Returns NULL when no more environments.
+ * Iterate through tests.  Pass in NULL for cenv to begin the iteration. For
+ * subsequent iterations, use the return value from the previous iteration.
+ * Returns NULL when there are no more environments.
  */
 struct compile_env *
 sym_test_env(struct sym_test *st, struct compile_env *cenv, int *need)
 {
         int i = cenv ? cenv->index + 1: 0;

@@ -580,10 +636,14 @@
         char *buf = NULL;
         size_t cap = 0;
         int line = 1;
 
         f = fopen(path, "r");
+        if (f == NULL) {
+                test_debugf(t, "fopen(%s): %s", path, strerror(errno));
+                return;
+        }
 
         test_debugf(t, "----->> begin (%s) <<------", path);
         while (getline(&buf, &cap, f) >= 0) {
                 (void) strtok(buf, "\r\n");
                 test_debugf(t, "%d: %s", line, buf);

@@ -609,10 +669,15 @@
         if (cfile != NULL) {
                 (void) unlink(cfile);
                 free(cfile);
                 cfile = NULL;
         }
+        if (efile != NULL) {
+                (void) unlink(efile);
+                free(efile);
+                efile = NULL;
+        }
         if (dname) {
                 (void) rmdir(dname);
                 free(dname);
                 dname = NULL;
         }

@@ -629,14 +694,15 @@
         (void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b));
         if ((d = mkdtemp(b)) == NULL) {
                 perror("mkdtemp");
                 return (-1);
         }
-        dname = strdup(d);
-        (void) asprintf(&cfile, "%s/compile_test.c", d);
-        (void) asprintf(&ofile, "%s/compile_test.o", d);
-        (void) asprintf(&lfile, "%s/compile_test.log", d);
+        dname = mystrdup(d);
+        myasprintf(&cfile, "%s/compile_test.c", d);
+        myasprintf(&ofile, "%s/compile_test.o", d);
+        myasprintf(&lfile, "%s/compile_test.log", d);
+        myasprintf(&efile, "%s/compile_test.exe", d);
         return (0);
 }
 
 void
 find_compiler(void)

@@ -646,10 +712,12 @@
         FILE *cf;
 
         t = test_start("finding compiler");
 
         if ((cf = fopen(cfile, "w+")) == NULL) {
+                test_failed(t, "Unable to open %s for write: %s", cfile,
+                    strerror(errno));
                 return;
         }
         (void) fprintf(cf, "#include <stdio.h>\n");
         (void) fprintf(cf, "int main(int argc, char **argv) {\n");
         (void) fprintf(cf, "#if defined(__SUNPRO_C)\n");

@@ -659,26 +727,26 @@
         (void) fprintf(cf, "#else\n");
         (void) fprintf(cf, "exit(99)\n");
         (void) fprintf(cf, "#endif\n}\n");
         (void) fclose(cf);
 
-        for (i = 0; compilers[i/2] != NULL; i++) {
+        for (i = 0; compilers[i] != NULL; i++) {
                 char cmd[256];
                 int rv;
 
                 (void) snprintf(cmd, sizeof (cmd),
-                    "%s%s %s %s -o %s >/dev/null 2>&1",
-                    puname[i%2], compilers[i/2], MFLAG, cfile, ofile);
+                    "%s %s %s -o %s >/dev/null 2>&1",
+                    compilers[i], MFLAG, cfile, efile);
                 test_debugf(t, "trying %s", cmd);
                 rv = system(cmd);
 
                 test_debugf(t, "result: %d", rv);
 
                 if ((rv < 0) || !WIFEXITED(rv) || WEXITSTATUS(rv) != 0)
                         continue;
 
-                rv = system(ofile);
+                rv = system(efile);
                 if (rv >= 0 && WIFEXITED(rv)) {
                         rv = WEXITSTATUS(rv);
                 } else {
                         rv = -1;
                 }

@@ -705,12 +773,11 @@
                         test_passed(t);
                         break;
                 default:
                         continue;
                 }
-                (void) asprintf(&compiler,
-                    "%s%s", puname[i%2], compilers[i/2]);
+                myasprintf(&compiler, "%s", compilers[i]);
                 test_debugf(t, "compiler: %s", compiler);
                 return;
         }
         test_failed(t, "No compiler found.");
 }

@@ -740,22 +807,18 @@
                 return (-1);
         }
 
         (void) unlink(ofile);
 
-        if (asprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1",
+        myasprintf(&cmd, "%s %s %s -c %s -o %s >>%s 2>&1",
             compiler, strcmp(env_lang(cenv), "c99") == 0 ? c99flags : c89flags,
-            env_defs(cenv), cfile, ofile, lfile) < 0) {
-                test_failed(t, "asprintf: %s", strerror(errno));
-                return (-1);
-        }
+            env_defs(cenv), cfile, ofile, lfile);
 
         if (extra_debug) {
                 test_debugf(t, "command: %s", cmd);
         }
 
-
         if ((logf = fopen(lfile, "w+")) == NULL) {
                 test_failed(t, "fopen: %s", strerror(errno));
                 return (-1);
         }
         (void) fprintf(logf, "===================\n");

@@ -762,24 +825,31 @@
         (void) fprintf(logf, "PROGRAM:\n%s\n", sym_test_prog(st));
         (void) fprintf(logf, "COMMAND: %s\n", cmd);
         (void) fprintf(logf, "EXPECT: %s\n", need ? "OK" : "FAIL");
         (void) fclose(logf);
 
-        if (system(cmd) != 0) {
-                if (need) {
+        switch (system(cmd)) {
+        case -1:
+                test_failed(t, "error compiling in %s: %s", env_name(cenv),
+                    strerror(errno));
+                return (-1);
+        case 0:
+                if (!need) {
                         fail_count++;
                         show_file(t, lfile);
-                        test_failed(t, "error compiling in %s", env_name(cenv));
+                        test_failed(t, "symbol visible in %s", env_name(cenv));
                         return (-1);
                 }
-        } else {
-                if (!need) {
+                break;
+        default:
+                if (need) {
                         fail_count++;
                         show_file(t, lfile);
-                        test_failed(t, "symbol visible in %s", env_name(cenv));
+                        test_failed(t, "error compiling in %s", env_name(cenv));
                         return (-1);
                 }
+                break;
         }
         good_count++;
         return (0);
 }
 

@@ -858,11 +928,14 @@
                     NULL) < 0) {
                         exit(1);
                 }
         }
 
-        (void) atexit(cleanup);
+        if (atexit(cleanup) != 0) {
+                perror("atexit");
+                exit(1);
+        }
 
         if (mkworkdir() < 0) {
                 perror("mkdir");
                 exit(1);
         }