@@ -11,6 +11,7 @@ import (
11
11
"go/token"
12
12
"go/types"
13
13
"sort"
14
+ "strconv"
14
15
"strings"
15
16
"unicode"
16
17
"unicode/utf8"
@@ -21,6 +22,7 @@ type importer struct {
21
22
data []byte
22
23
path string
23
24
buf []byte // for reading strings
25
+ version int // export format version
24
26
25
27
// object lists
26
28
strList []string // in order of appearance
@@ -40,17 +42,28 @@ type importer struct {
40
42
41
43
// BImportData imports a package from the serialized package data
42
44
// and returns the number of bytes consumed and a reference to the package.
43
- // If data is obviously malformed, an error is returned but in
44
- // general it is not recommended to call BImportData on untrusted data.
45
- func BImportData (imports map [string ]* types.Package , data []byte , path string ) (int , * types.Package , error ) {
45
+ // If the export data version is not recognized or the format is otherwise
46
+ // compromised, an error is returned.
47
+ func BImportData (imports map [string ]* types.Package , data []byte , path string ) (_ int , _ * types.Package , err error ) {
48
+ // catch panics and return them as errors
49
+ defer func () {
50
+ if e := recover (); e != nil {
51
+ // The package (filename) causing the problem is added to this
52
+ // error by a wrapper in the caller (Import in gcimporter.go).
53
+ err = fmt .Errorf ("cannot import, possibly version skew (%v) - reinstall package" , e )
54
+ }
55
+ }()
56
+
46
57
p := importer {
47
58
imports : imports ,
48
59
data : data ,
49
60
path : path ,
61
+ version : - 1 , // unknown version
50
62
strList : []string {"" }, // empty string is mapped to 0
51
63
}
52
64
53
65
// read version info
66
+ var versionstr string
54
67
if b := p .rawByte (); b == 'c' || b == 'd' {
55
68
// Go1.7 encoding; first byte encodes low-level
56
69
// encoding format (compact vs debug).
@@ -63,19 +76,34 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
63
76
}
64
77
p .trackAllTypes = p .rawByte () == 'a'
65
78
p .posInfoFormat = p .int () != 0
66
- const go17version = "v1"
67
- if s := p . string (); s != go17version {
68
- return p . read , nil , fmt . Errorf ( "importer: unknown export data format: %s (imported package compiled with old compiler?)" , s )
79
+ versionstr = p . string ()
80
+ if versionstr == "v1" {
81
+ p . version = 0
69
82
}
70
83
} else {
71
84
// Go1.8 extensible encoding
72
- const exportVersion = "version 1"
73
- if s := p .rawStringln (b ); s != exportVersion {
74
- return p .read , nil , fmt .Errorf ("importer: unknown export data format: %s (imported package compiled with old compiler?)" , s )
85
+ // read version string and extract version number (ignore anything after the version number)
86
+ versionstr = p .rawStringln (b )
87
+ if s := strings .SplitN (versionstr , " " , 3 ); len (s ) >= 2 && s [0 ] == "version" {
88
+ if v , err := strconv .Atoi (s [1 ]); err == nil && v > 0 {
89
+ p .version = v
90
+ }
75
91
}
92
+ }
93
+
94
+ // read version specific flags - extend as necessary
95
+ switch p .version {
96
+ // case 2:
97
+ // ...
98
+ // fallthrough
99
+ case 1 :
76
100
p .debugFormat = p .rawStringln (p .rawByte ()) == "debug"
77
101
p .trackAllTypes = p .int () != 0
78
102
p .posInfoFormat = p .int () != 0
103
+ case 0 :
104
+ // Go1.7 encoding format - nothing to do here
105
+ default :
106
+ errorf ("unknown export format version %d (%q)" , p .version , versionstr )
79
107
}
80
108
81
109
// --- generic export data ---
@@ -99,7 +127,7 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
99
127
100
128
// self-verification
101
129
if count := p .int (); count != objcount {
102
- panic ( fmt . Sprintf ( "got %d objects; want %d" , objcount , count ) )
130
+ errorf ( "got %d objects; want %d" , objcount , count )
103
131
}
104
132
105
133
// ignore compiler-specific import data
@@ -127,6 +155,10 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
127
155
return p .read , pkg , nil
128
156
}
129
157
158
+ func errorf (format string , args ... interface {}) {
159
+ panic (fmt .Sprintf (format , args ... ))
160
+ }
161
+
130
162
func (p * importer ) pkg () * types.Package {
131
163
// if the package was seen before, i is its index (>= 0)
132
164
i := p .tagOrIndex ()
@@ -136,7 +168,7 @@ func (p *importer) pkg() *types.Package {
136
168
137
169
// otherwise, i is the package tag (< 0)
138
170
if i != packageTag {
139
- panic ( fmt . Sprintf ( "unexpected package tag %d" , i ) )
171
+ errorf ( "unexpected package tag %d" , i )
140
172
}
141
173
142
174
// read package data
@@ -145,13 +177,13 @@ func (p *importer) pkg() *types.Package {
145
177
146
178
// we should never see an empty package name
147
179
if name == "" {
148
- panic ("empty package name in import" )
180
+ errorf ("empty package name in import" )
149
181
}
150
182
151
183
// an empty path denotes the package we are currently importing;
152
184
// it must be the first package we see
153
185
if (path == "" ) != (len (p .pkgList ) == 0 ) {
154
- panic ( fmt . Sprintf ( "package path %q for pkg index %d" , path , len (p .pkgList ) ))
186
+ errorf ( "package path %q for pkg index %d" , path , len (p .pkgList ))
155
187
}
156
188
157
189
// if the package was imported before, use that one; otherwise create a new one
@@ -163,7 +195,7 @@ func (p *importer) pkg() *types.Package {
163
195
pkg = types .NewPackage (path , name )
164
196
p .imports [path ] = pkg
165
197
} else if pkg .Name () != name {
166
- panic ( fmt . Sprintf ( "conflicting names %s and %s for package %q" , pkg .Name (), name , path ) )
198
+ errorf ( "conflicting names %s and %s for package %q" , pkg .Name (), name , path )
167
199
}
168
200
p .pkgList = append (p .pkgList , pkg )
169
201
@@ -180,7 +212,7 @@ func (p *importer) declare(obj types.Object) {
180
212
// imported.
181
213
// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
182
214
// switch case importing functions).
183
- panic ( fmt . Sprintf ( "inconsistent import:\n \t %v\n previously imported as:\n \t %v\n " , alt , obj ) )
215
+ errorf ( "inconsistent import:\n \t %v\n previously imported as:\n \t %v\n " , alt , obj )
184
216
}
185
217
}
186
218
@@ -211,7 +243,7 @@ func (p *importer) obj(tag int) {
211
243
p .declare (types .NewFunc (token .NoPos , pkg , name , sig ))
212
244
213
245
default :
214
- panic ( fmt . Sprintf ( "unexpected object tag %d" , tag ) )
246
+ errorf ( "unexpected object tag %d" , tag )
215
247
}
216
248
}
217
249
@@ -283,7 +315,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
283
315
}
284
316
285
317
if _ , ok := obj .(* types.TypeName ); ! ok {
286
- panic ( fmt . Sprintf ( "pkg = %s, name = %s => %s" , parent , name , obj ) )
318
+ errorf ( "pkg = %s, name = %s => %s" , parent , name , obj )
287
319
}
288
320
289
321
// associate new named type with obj if it doesn't exist yet
@@ -390,7 +422,7 @@ func (p *importer) typ(parent *types.Package) types.Type {
390
422
391
423
// no embedded interfaces with gc compiler
392
424
if p .int () != 0 {
393
- panic ("unexpected embedded interface" )
425
+ errorf ("unexpected embedded interface" )
394
426
}
395
427
396
428
t := types .NewInterface (p .methodList (parent ), nil )
@@ -426,14 +458,15 @@ func (p *importer) typ(parent *types.Package) types.Type {
426
458
case 3 /* Cboth */ :
427
459
dir = types .SendRecv
428
460
default :
429
- panic ( fmt . Sprintf ( "unexpected channel dir %d" , d ) )
461
+ errorf ( "unexpected channel dir %d" , d )
430
462
}
431
463
val := p .typ (parent )
432
464
* t = * types .NewChan (dir , val )
433
465
return t
434
466
435
467
default :
436
- panic (fmt .Sprintf ("unexpected type tag %d" , i ))
468
+ errorf ("unexpected type tag %d" , i )
469
+ panic ("unreachable" )
437
470
}
438
471
}
439
472
@@ -464,7 +497,7 @@ func (p *importer) field(parent *types.Package) *types.Var {
464
497
case * types.Named :
465
498
name = typ .Obj ().Name ()
466
499
default :
467
- panic ("anonymous field expected" )
500
+ errorf ("anonymous field expected" )
468
501
}
469
502
anonymous = true
470
503
}
@@ -498,6 +531,10 @@ func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
498
531
// use the imported package instead
499
532
pkg = p .pkgList [0 ]
500
533
}
534
+ if p .version == 0 && name == "_" {
535
+ // version 0 didn't export a package for _ fields
536
+ return pkg , name
537
+ }
501
538
if name != "" && ! exported (name ) {
502
539
if name == "?" {
503
540
name = ""
@@ -539,7 +576,7 @@ func (p *importer) param(named bool) (*types.Var, bool) {
539
576
if named {
540
577
name = p .string ()
541
578
if name == "" {
542
- panic ("expected named parameter" )
579
+ errorf ("expected named parameter" )
543
580
}
544
581
if name != "_" {
545
582
pkg = p .pkg ()
@@ -577,7 +614,8 @@ func (p *importer) value() constant.Value {
577
614
case stringTag :
578
615
return constant .MakeString (p .string ())
579
616
default :
580
- panic (fmt .Sprintf ("unexpected value tag %d" , tag ))
617
+ errorf ("unexpected value tag %d" , tag )
618
+ panic ("unreachable" )
581
619
}
582
620
}
583
621
@@ -640,7 +678,7 @@ func (p *importer) tagOrIndex() int {
640
678
func (p * importer ) int () int {
641
679
x := p .int64 ()
642
680
if int64 (int (x )) != x {
643
- panic ("exported integer too large" )
681
+ errorf ("exported integer too large" )
644
682
}
645
683
return int (x )
646
684
}
@@ -679,20 +717,20 @@ func (p *importer) string() string {
679
717
680
718
func (p * importer ) marker (want byte ) {
681
719
if got := p .rawByte (); got != want {
682
- panic ( fmt . Sprintf ( "incorrect marker: got %c; want %c (pos = %d)" , got , want , p .read ) )
720
+ errorf ( "incorrect marker: got %c; want %c (pos = %d)" , got , want , p .read )
683
721
}
684
722
685
723
pos := p .read
686
724
if n := int (p .rawInt64 ()); n != pos {
687
- panic ( fmt . Sprintf ( "incorrect position: got %d; want %d" , n , pos ) )
725
+ errorf ( "incorrect position: got %d; want %d" , n , pos )
688
726
}
689
727
}
690
728
691
729
// rawInt64 should only be used by low-level decoders.
692
730
func (p * importer ) rawInt64 () int64 {
693
731
i , err := binary .ReadVarint (p )
694
732
if err != nil {
695
- panic ( fmt . Sprintf ( "read error: %v" , err ) )
733
+ errorf ( "read error: %v" , err )
696
734
}
697
735
return i
698
736
}
@@ -727,7 +765,7 @@ func (p *importer) rawByte() byte {
727
765
case '|' :
728
766
// nothing to do
729
767
default :
730
- panic ("unexpected escape sequence in export data" )
768
+ errorf ("unexpected escape sequence in export data" )
731
769
}
732
770
}
733
771
p .data = p .data [r :]
0 commit comments