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);
}