Print this page
Incorporate rmustacc's review feedback.

*** 8,25 **** * 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> */ /* * 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> --- 8,23 ---- * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* ! * Copyright 2015 Garrett D'Amore <garrett@damore.org> */ /* * This program tests symbol visibility using the /usr/bin/c89 and * /usr/bin/c99 programs. */ #include <stdio.h> #include <stdlib.h> #include <string.h>
*** 34,43 **** --- 32,42 ---- 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,88 **** "/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 MAXHDR 10 /* maximum # headers to require to access symbol */ #define MAXARG 20 /* maximum # of arguments */ #define WS " \t" --- 59,73 ---- "/opt/sfw/bin/gcc", "/usr/local/bin/gcc", NULL }; char *compiler = NULL; const char *c89flags = NULL; const char *c99flags = NULL; ! #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,130 **** --- 105,151 ---- 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,234 **** char *name; char *lang; char *defs; if (nfields != 3) { ! (void) asprintf(err, "number of fields (%d) != 3", nfields); return (-1); } if (next_env >= MAXENV) { ! (void) asprintf(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].index = next_env; next_env++; return (0); } --- 230,255 ---- char *name; char *lang; char *defs; if (nfields != 3) { ! myasprintf(err, "number of fields (%d) != 3", nfields); return (-1); } if (next_env >= MAXENV) { ! myasprintf(err, "too many environments"); return (-1); } name = fields[0]; lang = fields[1]; defs = fields[2]; ! 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,383 **** struct env_group *eg; uint64_t mask; char *item; if (nfields != 2) { ! (void) asprintf(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); return (-1); } ! eg = calloc(1, sizeof (*eg)); ! eg->name = strdup(name); eg->mask = mask; eg->next = env_groups; env_groups = eg; return (0); } static void mkprog(struct sym_test *st) { - static char buf[2048]; char *s; - char *prog = buf; ! *prog = 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]); } for (s = st->rtype; *s; s++) { ! ADDCHR(prog, *s); if (*s == '(') { s++; ! ADDCHR(prog, *s); s++; break; } } ! ADDCHR(prog, ' '); /* for function pointers, s is closing suffix, otherwise empty */ switch (st->type) { case SYM_TYPE: ! ADDFMT(prog, "test_type;", st->rtype); 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); break; case SYM_FUNC: ! ADDSTR(prog, "\ntest_func("); for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) { int didname = 0; if (i > 0) { ! ADDSTR(prog, ", "); } if (strcmp(st->atypes[i], "void") == 0) { didname = 1; } if (strcmp(st->atypes[i], "") == 0) { didname = 1; ! ADDSTR(prog, "void"); } /* print the argument list */ for (char *a = st->atypes[i]; *a; a++) { if (*a == '(' && a[1] == '*' && !didname) { ! ADDFMT(prog, "(*a%d", i); didname = 1; a++; } else if (*a == '[' && !didname) { ! ADDFMT(prog, "a%d[", i); didname = 1; } else { ! ADDCHR(prog, *a); } } if (!didname) { ! ADDFMT(prog, " a%d", i); } } if (st->atypes[0] == NULL) { ! ADDSTR(prog, "void"); } /* close argument list, and closing ")" for func ptrs */ ! ADDFMT(prog, ")%s\n{\n\t", s); /* NB: s is normally empty */ if (strcmp(st->rtype, "") != 0 && strcmp(st->rtype, "void") != 0) { ! ADDSTR(prog, "return "); } /* add the function call */ ! ADDFMT(prog, "%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); } } ! ADDSTR(prog, ");\n}"); break; } ! ADDCHR(prog, '\n'); ! st->prog = strdup(buf); } 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); return (-1); } return (0); } --- 261,438 ---- struct env_group *eg; uint64_t mask; char *item; if (nfields != 2) { ! 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) { ! myasprintf(err, "reference to undefined env %s", item); return (-1); } ! 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) { char *s; ! proglen = 0; for (int i = 0; i < MAXHDR && st->hdrs[i] != NULL; i++) { ! addprogfmt("#include <%s>\n", st->hdrs[i]); } for (s = st->rtype; *s; s++) { ! addprogch(*s); if (*s == '(') { s++; ! addprogch(*s); s++; break; } } ! addprogch(' '); /* for function pointers, s is closing suffix, otherwise empty */ switch (st->type) { case SYM_TYPE: ! addprogstr("test_type;"); break; case SYM_VALUE: ! 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: ! addprogstr("\ntest_func("); for (int i = 0; st->atypes[i] != NULL && i < MAXARG; i++) { int didname = 0; if (i > 0) { ! addprogstr(", "); } if (strcmp(st->atypes[i], "void") == 0) { didname = 1; } if (strcmp(st->atypes[i], "") == 0) { didname = 1; ! addprogstr("void"); } /* print the argument list */ for (char *a = st->atypes[i]; *a; a++) { if (*a == '(' && a[1] == '*' && !didname) { ! addprogfmt("(*a%d", i); didname = 1; a++; } else if (*a == '[' && !didname) { ! addprogfmt("a%d[", i); didname = 1; } else { ! addprogch(*a); } } if (!didname) { ! addprogfmt(" a%d", i); } } if (st->atypes[0] == NULL) { ! addprogstr("void"); } /* close argument list, and closing ")" for func ptrs */ ! addprogfmt(")%s\n{\n\t", s); /* NB: s is normally empty */ if (strcmp(st->rtype, "") != 0 && strcmp(st->rtype, "void") != 0) { ! addprogstr("return "); } /* add the function call */ ! 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) { ! addprogfmt("%sa%d", i > 0 ? ", " : "", i); } } ! addprogstr(");\n}"); break; } ! addprogch('\n'); ! 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) { ! myasprintf(err, "bad env action %s", item); return (-1); } return (0); }
*** 386,400 **** { int i = 0; for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) { if (i >= MAXHDR) { ! (void) asprintf(err, "too many headers"); return (-1); } test_trim(&h); ! st->hdrs[i++] = strdup(h); } return (0); } --- 441,455 ---- { int i = 0; for (char *h = strsep(&hdrs, ";"); h != NULL; h = strsep(&hdrs, ";")) { if (i >= MAXHDR) { ! myasprintf(err, "too many headers"); return (-1); } test_trim(&h); ! st->hdrs[i++] = mystrdup(h); } return (0); }
*** 403,417 **** { int i = 0; char *a; for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) { if (i >= MAXARG) { ! (void) asprintf(err, "too many arguments"); return (-1); } test_trim(&a); ! st->atypes[i++] = strdup(a); } return (0); } --- 458,472 ---- { int i = 0; char *a; for (a = strsep(&atype, ";"); a != NULL; a = strsep(&atype, ";")) { if (i >= MAXARG) { ! myasprintf(err, "too many arguments"); return (-1); } test_trim(&a); ! st->atypes[i++] = mystrdup(a); } return (0); }
*** 422,442 **** char *hdrs; char *envs; struct sym_test *st; if (nfields != 3) { ! (void) asprintf(err, "number of fields (%d) != 3", nfields); return (-1); } decl = fields[0]; hdrs = fields[1]; envs = fields[2]; ! st = calloc(1, sizeof (*st)); st->type = SYM_TYPE; ! st->name = strdup(decl); ! st->rtype = strdup(decl); if ((add_envs(st, envs, err) < 0) || (add_headers(st, hdrs, err) < 0)) { return (-1); } --- 477,497 ---- char *hdrs; char *envs; struct sym_test *st; if (nfields != 3) { ! myasprintf(err, "number of fields (%d) != 3", nfields); return (-1); } decl = fields[0]; hdrs = fields[1]; envs = fields[2]; ! st = myzalloc(sizeof (*st)); st->type = SYM_TYPE; ! st->name = mystrdup(decl); ! st->rtype = mystrdup(decl); if ((add_envs(st, envs, err) < 0) || (add_headers(st, hdrs, err) < 0)) { return (-1); }
*** 453,474 **** char *hdrs; char *envs; struct sym_test *st; if (nfields != 4) { ! (void) asprintf(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->type = SYM_VALUE; ! st->name = strdup(name); ! st->rtype = strdup(type); if ((add_envs(st, envs, err) < 0) || (add_headers(st, hdrs, err) < 0)) { return (-1); } --- 508,529 ---- char *hdrs; char *envs; struct sym_test *st; if (nfields != 4) { ! myasprintf(err, "number of fields (%d) != 4", nfields); return (-1); } name = fields[0]; type = fields[1]; hdrs = fields[2]; envs = fields[3]; ! st = myzalloc(sizeof (*st)); st->type = SYM_VALUE; ! st->name = mystrdup(name); ! st->rtype = mystrdup(type); if ((add_envs(st, envs, err) < 0) || (add_headers(st, hdrs, err) < 0)) { return (-1); }
*** 486,508 **** char *hdrs; char *envs; struct sym_test *st; if (nfields != 5) { ! (void) asprintf(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->type = SYM_FUNC; ! st->name = strdup(name); ! st->rtype = strdup(rtype); if ((add_envs(st, envs, err) < 0) || (add_headers(st, hdrs, err) < 0) || (add_arg_types(st, atype, err) < 0)) { return (-1); --- 541,563 ---- char *hdrs; char *envs; struct sym_test *st; if (nfields != 5) { ! 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 = myzalloc(sizeof (*st)); st->type = SYM_FUNC; ! 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,543 **** { return (st->name); } /* ! * Iterate through tests. Pass NULL for cenv first time, and previous result ! * the next. Returns NULL when 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; --- 587,599 ---- { return (st->name); } /* ! * 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,589 **** --- 636,649 ---- 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,618 **** --- 669,683 ---- 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,642 **** (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); return (0); } void find_compiler(void) --- 694,708 ---- (void) strlcpy(b, "/tmp/symbols_testXXXXXX", sizeof (b)); if ((d = mkdtemp(b)) == NULL) { perror("mkdtemp"); return (-1); } ! 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,655 **** --- 712,723 ---- 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,684 **** (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++) { 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); 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); if (rv >= 0 && WIFEXITED(rv)) { rv = WEXITSTATUS(rv); } else { rv = -1; } --- 727,752 ---- (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] != NULL; i++) { char cmd[256]; int rv; (void) snprintf(cmd, sizeof (cmd), ! "%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(efile); if (rv >= 0 && WIFEXITED(rv)) { rv = WEXITSTATUS(rv); } else { rv = -1; }
*** 705,716 **** test_passed(t); break; default: continue; } ! (void) asprintf(&compiler, ! "%s%s", puname[i%2], compilers[i/2]); test_debugf(t, "compiler: %s", compiler); return; } test_failed(t, "No compiler found."); } --- 773,783 ---- test_passed(t); break; default: continue; } ! myasprintf(&compiler, "%s", compilers[i]); test_debugf(t, "compiler: %s", compiler); return; } test_failed(t, "No compiler found."); }
*** 740,761 **** return (-1); } (void) unlink(ofile); ! if (asprintf(&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); ! } 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"); --- 807,824 ---- return (-1); } (void) unlink(ofile); ! 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); 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,785 **** (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) { fail_count++; show_file(t, lfile); ! test_failed(t, "error compiling in %s", env_name(cenv)); return (-1); } ! } else { ! if (!need) { fail_count++; show_file(t, lfile); ! test_failed(t, "symbol visible in %s", env_name(cenv)); return (-1); } } good_count++; return (0); } --- 825,855 ---- (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); ! 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, "symbol visible in %s", env_name(cenv)); return (-1); } ! break; ! default: ! if (need) { fail_count++; show_file(t, lfile); ! test_failed(t, "error compiling in %s", env_name(cenv)); return (-1); } + break; } good_count++; return (0); }
*** 858,868 **** NULL) < 0) { exit(1); } } ! (void) atexit(cleanup); if (mkworkdir() < 0) { perror("mkdir"); exit(1); } --- 928,941 ---- NULL) < 0) { exit(1); } } ! if (atexit(cleanup) != 0) { ! perror("atexit"); ! exit(1); ! } if (mkworkdir() < 0) { perror("mkdir"); exit(1); }