Fixed a race condition in builder/vmware/common/driver_parser.go due to a misunderstanding how channels work when you close them.

This commit is contained in:
Ali Rizvi-Santiago 2017-11-22 17:11:13 -06:00
parent 737e951685
commit 594ed950c7
1 changed files with 39 additions and 22 deletions

View File

@ -17,8 +17,9 @@ type sentinelSignaller chan struct{}
/** low-level parsing */
// strip the comments and extraneous newlines from a byte channel
func uncomment(eof sentinelSignaller, in <-chan byte) chan byte {
func uncomment(eof sentinelSignaller, in <-chan byte) (chan byte, sentinelSignaller) {
out := make(chan byte)
eoc := make(sentinelSignaller)
go func(in <-chan byte, out chan byte) {
var endofline bool
@ -40,16 +41,19 @@ func uncomment(eof sentinelSignaller, in <-chan byte) chan byte {
}
}
}
close(eoc)
}(in, out)
return out
return out, eoc
}
// convert a byte channel into a channel of pseudo-tokens
func tokenizeDhcpConfig(eof sentinelSignaller, in chan byte) chan string {
func tokenizeDhcpConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
var ch byte
var state string
var quote bool
eot := make(sentinelSignaller)
out := make(chan string)
go func(out chan string) {
for stillReading := true; stillReading; {
@ -106,8 +110,9 @@ func tokenizeDhcpConfig(eof sentinelSignaller, in chan byte) chan string {
if len(state) > 0 {
out <- state
}
close(eot)
}(out)
return out
return out, eot
}
/** mid-level parsing */
@ -220,12 +225,14 @@ func parseDhcpConfig(eof sentinelSignaller, in chan string) (tkGroup, error) {
return result, nil
}
func tokenizeNetworkMapConfig(eof sentinelSignaller, in chan byte) chan string {
func tokenizeNetworkMapConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
var ch byte
var state string
var quote bool
var lastnewline bool
eot := make(sentinelSignaller)
out := make(chan string)
go func(out chan string) {
for stillReading := true; stillReading; {
@ -291,8 +298,9 @@ func tokenizeNetworkMapConfig(eof sentinelSignaller, in chan byte) chan string {
if len(state) > 0 {
out <- state
}
close(eot)
}(out)
return out
return out, eot
}
func parseNetworkMapConfig(eof sentinelSignaller, in chan string) (NetworkMap, error) {
@ -966,9 +974,9 @@ type DhcpConfiguration []configDeclaration
func ReadDhcpConfiguration(fd *os.File) (DhcpConfiguration, error) {
fromfile, eof := consumeFile(fd)
uncommented := uncomment(eof, fromfile)
tokenized := tokenizeDhcpConfig(eof, uncommented)
parsetree, err := parseDhcpConfig(eof, tokenized)
uncommented, eoc := uncomment(eof, fromfile)
tokenized, eot := tokenizeDhcpConfig(eoc, uncommented)
parsetree, err := parseDhcpConfig(eot, tokenized)
if err != nil {
return nil, err
}
@ -1064,10 +1072,10 @@ type NetworkNameMapper interface {
func ReadNetworkMap(fd *os.File) (NetworkMap, error) {
fromfile, eof := consumeFile(fd)
uncommented := uncomment(eof, fromfile)
tokenized := tokenizeNetworkMapConfig(eof, uncommented)
uncommented, eoc := uncomment(eof, fromfile)
tokenized, eot := tokenizeNetworkMapConfig(eoc, uncommented)
result, err := parseNetworkMapConfig(eof, tokenized)
result, err := parseNetworkMapConfig(eot, tokenized)
if err != nil {
return nil, err
}
@ -1100,11 +1108,13 @@ func (e *NetworkMap) repr() string {
}
/*** parser for VMware Fusion's networking file */
func tokenizeNetworkingConfig(eof sentinelSignaller, in chan byte) chan string {
func tokenizeNetworkingConfig(eof sentinelSignaller, in chan byte) (chan string, sentinelSignaller) {
var ch byte
var state string
var repeat_newline bool
eot := make(sentinelSignaller)
out := make(chan string)
go func(out chan string) {
for reading := true; reading; {
@ -1144,13 +1154,16 @@ func tokenizeNetworkingConfig(eof sentinelSignaller, in chan byte) chan string {
if len(state) > 0 {
out <- state
}
close(eot)
}(out)
return out
return out, eot
}
func splitNetworkingConfig(eof sentinelSignaller, in chan string) chan []string {
func splitNetworkingConfig(eof sentinelSignaller, in chan string) (chan []string, sentinelSignaller) {
var out chan []string
eos := make(sentinelSignaller)
out = make(chan []string)
go func(out chan []string) {
row := make([]string, 0)
@ -1174,8 +1187,9 @@ func splitNetworkingConfig(eof sentinelSignaller, in chan string) chan []string
if len(row) > 0 {
out <- row
}
close(eos)
}(out)
return out
return out, eos
}
/// All token types in networking file.
@ -1642,9 +1656,11 @@ func NetworkingParserByCommand(command string) *func([]string) (*networkingComma
return nil
}
func parseNetworkingConfig(eof sentinelSignaller, rows chan []string) chan networkingCommandEntry {
func parseNetworkingConfig(eof sentinelSignaller, rows chan []string) (chan networkingCommandEntry, sentinelSignaller) {
var out chan networkingCommandEntry
eop := make(sentinelSignaller)
out = make(chan networkingCommandEntry)
go func(in chan []string, out chan networkingCommandEntry) {
for reading := true; reading; {
@ -1668,8 +1684,9 @@ func parseNetworkingConfig(eof sentinelSignaller, rows chan []string) chan netwo
}
}
}
close(eop)
}(rows, out)
return out
return out, eop
}
type NetworkingConfig struct {
@ -1795,9 +1812,9 @@ func flattenNetworkingConfig(eof sentinelSignaller, in chan networkingCommandEnt
func ReadNetworkingConfig(fd *os.File) (NetworkingConfig, error) {
// start piecing together different parts of the file
fromfile, eof := consumeFile(fd)
tokenized := tokenizeNetworkingConfig(eof, fromfile)
rows := splitNetworkingConfig(eof, tokenized)
entries := parseNetworkingConfig(eof, rows)
tokenized, eot := tokenizeNetworkingConfig(eof, fromfile)
rows, eos := splitNetworkingConfig(eot, tokenized)
entries, eop := parseNetworkingConfig(eos, rows)
// parse the version
parsed_version, err := networkingReadVersion(<-rows)
@ -1812,7 +1829,7 @@ func ReadNetworkingConfig(fd *os.File) (NetworkingConfig, error) {
}
// convert to a configuration
result := flattenNetworkingConfig(eof, entries)
result := flattenNetworkingConfig(eop, entries)
return result, nil
}