Commit dc38756c authored by Anthony Martin's avatar Anthony Martin Committed by Russ Cox

gc: reject import paths containing special characters

Also allow multiple invalid import statements in a
single file.

Fixes #3021. The changes to go/parser and the
language specifcation have already been committed.

R=rsc, gri
CC=golang-dev
https://golang.org/cl/5672084
parent 490c3d4a
...@@ -1171,6 +1171,7 @@ Type* getthisx(Type *t); ...@@ -1171,6 +1171,7 @@ Type* getthisx(Type *t);
int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr); int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
void importdot(Pkg *opkg, Node *pack); void importdot(Pkg *opkg, Node *pack);
int is64(Type *t); int is64(Type *t);
int isbadimport(Strlit *s);
int isblank(Node *n); int isblank(Node *n);
int isblanksym(Sym *s); int isblanksym(Sym *s);
int isfixedarray(Type *t); int isfixedarray(Type *t);
......
...@@ -205,7 +205,15 @@ import_stmt: ...@@ -205,7 +205,15 @@ import_stmt:
my->lastlineno = $1; my->lastlineno = $1;
my->block = 1; // at top level my->block = 1; // at top level
} }
| import_here import_there
{
// When an invalid import path is passed to importfile,
// it calls yyerror and then sets up a fake import with
// no package statement. This allows us to test more
// than one invalid import statement in a single file.
if(nerrors == 0)
fatal("phase error in import");
}
import_stmt_list: import_stmt_list:
import_stmt import_stmt
......
...@@ -573,6 +573,13 @@ findpkg(Strlit *name) ...@@ -573,6 +573,13 @@ findpkg(Strlit *name)
return 0; return 0;
} }
static void
fakeimport(void)
{
importpkg = mkpkg(strlit("fake"));
cannedimports("fake.6", "$$\n");
}
void void
importfile(Val *f, int line) importfile(Val *f, int line)
{ {
...@@ -589,17 +596,19 @@ importfile(Val *f, int line) ...@@ -589,17 +596,19 @@ importfile(Val *f, int line)
if(f->ctype != CTSTR) { if(f->ctype != CTSTR) {
yyerror("import statement not a string"); yyerror("import statement not a string");
fakeimport();
return; return;
} }
if(strlen(f->u.sval->s) != f->u.sval->len) { if(f->u.sval->len == 0) {
yyerror("import path contains NUL"); yyerror("import path is empty");
errorexit(); fakeimport();
return;
} }
if(strchr(f->u.sval->s, '\\')) { if(isbadimport(f->u.sval)) {
yyerror("import path contains backslash; use slash"); fakeimport();
errorexit(); return;
} }
// The package name main is no longer reserved, // The package name main is no longer reserved,
......
...@@ -3559,11 +3559,9 @@ mkpkg(Strlit *path) ...@@ -3559,11 +3559,9 @@ mkpkg(Strlit *path)
{ {
Pkg *p; Pkg *p;
int h; int h;
if(strlen(path->s) != path->len) { if(isbadimport(path))
yyerror("import path contains NUL byte");
errorexit(); errorexit();
}
h = stringhash(path->s) & (nelem(phash)-1); h = stringhash(path->s) & (nelem(phash)-1);
for(p=phash[h]; p; p=p->link) for(p=phash[h]; p; p=p->link)
...@@ -3612,3 +3610,41 @@ addinit(Node **np, NodeList *init) ...@@ -3612,3 +3610,41 @@ addinit(Node **np, NodeList *init)
n->ninit = concat(init, n->ninit); n->ninit = concat(init, n->ninit);
n->ullman = UINF; n->ullman = UINF;
} }
int
isbadimport(Strlit *path)
{
char *s;
Rune r;
if(strlen(path->s) != path->len) {
yyerror("import path contains NUL");
return 1;
}
s = path->s;
while(*s) {
s += chartorune(&r, s);
if(r == Runeerror) {
yyerror("import path contains invalid UTF-8 sequence");
return 1;
}
if(r < 0x20 || r == 0x7f) {
yyerror("import path contains control character");
return 1;
}
if(r == '\\') {
yyerror("import path contains backslash; use slash");
return 1;
}
if(isspacerune(r)) {
yyerror("import path contains space character");
return 1;
}
if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}~", r)) {
yyerror("import path contains invalid character '%C'", r);
return 1;
}
}
return 0;
}
This diff is collapsed.
/* A Bison parser, made by GNU Bison 2.5. */
/* A Bison parser, made by GNU Bison 2.4.1. */ /* Bison interface for Yacc-like parsers in C
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -148,7 +146,7 @@ ...@@ -148,7 +146,7 @@
typedef union YYSTYPE typedef union YYSTYPE
{ {
/* Line 1676 of yacc.c */ /* Line 2068 of yacc.c */
#line 28 "go.y" #line 28 "go.y"
Node* node; Node* node;
...@@ -160,8 +158,8 @@ typedef union YYSTYPE ...@@ -160,8 +158,8 @@ typedef union YYSTYPE
/* Line 1676 of yacc.c */ /* Line 2068 of yacc.c */
#line 165 "y.tab.h" #line 163 "y.tab.h"
} YYSTYPE; } YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define yystype YYSTYPE /* obsolescent; will be withdrawn */
......
...@@ -14,25 +14,25 @@ static struct { ...@@ -14,25 +14,25 @@ static struct {
// is converted by bisonerrors into the yystate and yychar caused // is converted by bisonerrors into the yystate and yychar caused
// by that token list. // by that token list.
220, ',', 221, ',',
"unexpected comma during import block", "unexpected comma during import block",
376, ';', 377, ';',
"unexpected semicolon or newline before {", "unexpected semicolon or newline before {",
397, ';', 398, ';',
"unexpected semicolon or newline before {", "unexpected semicolon or newline before {",
236, ';', 237, ';',
"unexpected semicolon or newline before {", "unexpected semicolon or newline before {",
473, LBODY, 474, LBODY,
"unexpected semicolon or newline before {", "unexpected semicolon or newline before {",
22, '{', 22, '{',
"unexpected semicolon or newline before {", "unexpected semicolon or newline before {",
143, ';', 144, ';',
"unexpected semicolon or newline in type declaration", "unexpected semicolon or newline in type declaration",
37, '}', 37, '}',
...@@ -44,30 +44,30 @@ static struct { ...@@ -44,30 +44,30 @@ static struct {
37, ',', 37, ',',
"unexpected comma in channel type", "unexpected comma in channel type",
436, LELSE, 437, LELSE,
"unexpected semicolon or newline before else", "unexpected semicolon or newline before else",
256, ',', 257, ',',
"name list not allowed in interface type", "name list not allowed in interface type",
236, LVAR, 237, LVAR,
"var declaration not allowed in for initializer", "var declaration not allowed in for initializer",
65, '{', 65, '{',
"unexpected { at end of statement", "unexpected { at end of statement",
375, '{', 376, '{',
"unexpected { at end of statement", "unexpected { at end of statement",
124, ';', 125, ';',
"argument to go/defer must be function call", "argument to go/defer must be function call",
424, ';', 425, ';',
"need trailing comma before newline in composite literal", "need trailing comma before newline in composite literal",
111, LNAME, 112, LNAME,
"nested func not allowed", "nested func not allowed",
614, ';', 615, ';',
"else must be followed by if or statement block" "else must be followed by if or statement block"
}; };
...@@ -4,10 +4,48 @@ ...@@ -4,10 +4,48 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Verify that imports with backslashes are rejected by the compiler. // Verify that invalid imports are rejected by the compiler.
// Does not compile. // Does not compile.
// TODO: make more thorough.
package main package main
import `net\http` // ERROR "backslash" // Correct import paths.
import _ "fmt"
import _ `time`
import _ "m\x61th"
import _ "go/parser"
// Correct import paths, but the packages don't exist.
// Don't test.
//import "a.b"
//import "greek/αβ"
// Import paths must be strings.
import 42 // ERROR "import statement"
import 'a' // ERROR "import statement"
import 3.14 // ERROR "import statement"
import 0.25i // ERROR "import statement"
// Each of these pairs tests both `` vs "" strings
// and also use of invalid characters spelled out as
// escape sequences and written directly.
// For example `"\x00"` tests import "\x00"
// while "`\x00`" tests import `<actual-NUL-byte>`.
import "" // ERROR "import path"
import `` // ERROR "import path"
import "\x00" // ERROR "import path"
import `\x00` // ERROR "import path"
import "\x7f" // ERROR "import path"
import `\x7f` // ERROR "import path"
import "a!" // ERROR "import path"
import `a!` // ERROR "import path"
import "a b" // ERROR "import path"
import `a b` // ERROR "import path"
import "a\\b" // ERROR "import path"
import `a\\b` // ERROR "import path"
import "\"`a`\"" // ERROR "import path"
import `\"a\"` // ERROR "import path"
import "\x80\x80" // ERROR "import path"
import `\x80\x80` // ERROR "import path"
import "\xFFFD" // ERROR "import path"
import `\xFFFD` // ERROR "import path"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment