From b9b204d55daaab264239f322cb3c13c57452cb2f Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 22 Jul 2011 21:18:03 -0400 Subject: [PATCH] ld: detect all import cycles Fixes #2052. R=r CC=golang-dev https://golang.org/cl/4812053 --- src/cmd/ld/go.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++- src/cmd/ld/lib.c | 3 + src/cmd/ld/lib.h | 2 + 3 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c index 05d1cc136c..1c77cca1a8 100644 --- a/src/cmd/ld/go.c +++ b/src/cmd/ld/go.c @@ -32,6 +32,7 @@ enum { }; static Import *ihash[NIHASH]; static int nimport; +static void imported(char *pkg, char *import); static int hashstr(char *name) @@ -308,12 +309,23 @@ loop: p += 6; else if(strncmp(p, "import ", 7) == 0) { p += 7; + while(p < ep && *p != ' ') + p++; + p++; + name = p; while(p < ep && *p != '\n') p++; + if(p >= ep) { + fprint(2, "%s: %s: confused in import line\n", argv0, file); + nerrors++; + return -1; + } + *p++ = '\0'; + imported(pkg, name); goto loop; } else { - fprint(2, "%s: confused in pkg data near <<%.40s>>\n", argv0, prefix); + fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix); nerrors++; return -1; } @@ -708,3 +720,150 @@ addexport(void) for(i=0; iargs, char*); + if(s == nil) + return fmtstrcpy(fp, ""); + + se = s + strlen(s); + while(s < se) { + n = chartorune(&r, s); + s += n; + switch(r) { + case Runeerror: + if(n == 1) { + fmtprint(fp, "\\x%02x", (uchar)*(s-1)); + break; + } + // fall through + default: + if(r < ' ') { + fmtprint(fp, "\\x%02x", r); + break; + } + fmtrune(fp, r); + break; + case '\t': + fmtstrcpy(fp, "\\t"); + break; + case '\n': + fmtstrcpy(fp, "\\n"); + break; + case '\"': + case '\\': + fmtrune(fp, '\\'); + fmtrune(fp, r); + break; + } + } + return 0; +} + + +typedef struct Pkg Pkg; +struct Pkg +{ + uchar mark; + uchar checked; + Pkg *next; + char *path; + Pkg **impby; + int nimpby; + int mimpby; + Pkg *all; +}; + +static Pkg *phash[1024]; +static Pkg *pkgall; + +static Pkg* +getpkg(char *path) +{ + Pkg *p; + int h; + + h = hashstr(path) % nelem(phash); + for(p=phash[h]; p; p=p->next) + if(strcmp(p->path, path) == 0) + return p; + p = mal(sizeof *p); + p->path = strdup(path); + p->next = phash[h]; + phash[h] = p; + p->all = pkgall; + pkgall = p; + return p; +} + +static void +imported(char *pkg, char *import) +{ + Pkg *p, *i; + + // everyone imports runtime, even runtime. + if(strcmp(import, "\"runtime\"") == 0) + return; + + pkg = smprint("\"%Z\"", pkg); // turn pkg path into quoted form, freed below + p = getpkg(pkg); + i = getpkg(import); + if(i->nimpby >= i->mimpby) { + i->mimpby *= 2; + if(i->mimpby == 0) + i->mimpby = 16; + i->impby = realloc(i->impby, i->mimpby*sizeof i->impby[0]); + } + i->impby[i->nimpby++] = p; + free(pkg); +} + +static Pkg* +cycle(Pkg *p) +{ + int i; + Pkg *bad; + + if(p->checked) + return 0; + + if(p->mark) { + nerrors++; + print("import cycle:\n"); + print("\t%s\n", p->path); + return p; + } + p->mark = 1; + for(i=0; inimpby; i++) { + if((bad = cycle(p->impby[i])) != nil) { + p->mark = 0; + p->checked = 1; + print("\timports %s\n", p->path); + if(bad == p) + return nil; + return bad; + } + } + p->checked = 1; + p->mark = 0; + return 0; +} + +void +importcycles(void) +{ + Pkg *p; + + for(p=pkgall; p; p=p->all) + cycle(p); +} + + + \ No newline at end of file diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index ebc4b0bf7f..86ed8476aa 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -62,6 +62,7 @@ libinit(void) { fmtinstall('i', iconv); fmtinstall('Y', Yconv); + fmtinstall('Z', Zconv); mywhatsys(); // get goroot, goarch, goos if(strcmp(goarch, thestring) != 0) print("goarch is not known: %s\n", goarch); @@ -281,6 +282,8 @@ loadlib(void) // binaries, so leave it enabled on OS X (Mach-O) binaries. if(!havedynamic && HEADTYPE != Hdarwin) debug['d'] = 1; + + importcycles(); } /* diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h index ee7eb87c00..03a1d5806d 100644 --- a/src/cmd/ld/lib.h +++ b/src/cmd/ld/lib.h @@ -302,3 +302,5 @@ vlong cpos(void); void cseek(vlong); void cseekend(void); void cwrite(void*, int); +void importcycles(void); +int Zconv(Fmt*); -- 2.50.0