all: avoid a goroutine deadlock on disassembler error

testExtDis currently has a goroutine deadlock - errc is an unbuffered
channel, which is written to from a goroutine that calls extdis. The
goroutine running testExtDis calls generate, which calls back into the
anonymous function which then reads from ext.Dis. If extdis returns an
error, it will not write to ext.Dis which leaves a deadlock between the
two goroutines - one writing on errc and one reading from ext.Dis.

Prevent this by closing the ext.Dis channel if we encounter an error
that would be written to errc. This results in all current and future
calls to the anonymous function returning, generate will then return
and errc will then be read. This is a minimal fix - this really needs
a redesign to improve the synchronisation and error handling (and
ideally it would be not duplicated for each architecture).

Change-Id: I9354b43608d25a55152d3ec989869c2afc076ee5
Reviewed-on: https://go-review.googlesource.com/c/arch/+/805180
Reviewed-by: Cherry Mui <cherryyz@google.com>
Auto-Submit: Joel Sing <joel@sing.id.au>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
diff --git a/arm/armasm/ext_test.go b/arm/armasm/ext_test.go
index f075862..f8d82a4 100644
--- a/arm/armasm/ext_test.go
+++ b/arm/armasm/ext_test.go
@@ -130,9 +130,15 @@
 
 		errors = make([]string, 0, 100) // sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
+
 	generate(func(enc []byte) {
 		dec, ok := <-ext.Dec
 		if !ok {
diff --git a/arm64/arm64asm/ext_test.go b/arm64/arm64asm/ext_test.go
index 839eb3f..2e8b759 100644
--- a/arm64/arm64asm/ext_test.go
+++ b/arm64/arm64asm/ext_test.go
@@ -149,8 +149,13 @@
 
 		errors = make([]string, 0, 100) // Sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
 
 	generate(func(enc []byte) {
@@ -204,7 +209,6 @@
 	if err := <-errc; err != nil {
 		t.Fatalf("external disassembler: %v", err)
 	}
-
 }
 
 // Start address of text.
diff --git a/loong64/loong64asm/ext_test.go b/loong64/loong64asm/ext_test.go
index 7d479dc..f4f2ec9 100644
--- a/loong64/loong64asm/ext_test.go
+++ b/loong64/loong64asm/ext_test.go
@@ -122,8 +122,13 @@
 
 		errors = make([]string, 0, 100) // Sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
 
 	generate(func(enc []byte) {
diff --git a/ppc64/ppc64asm/ext_test.go b/ppc64/ppc64asm/ext_test.go
index 806701b..36c95dc 100644
--- a/ppc64/ppc64asm/ext_test.go
+++ b/ppc64/ppc64asm/ext_test.go
@@ -128,9 +128,15 @@
 
 		errors = make([]string, 0, 100) // sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
+
 	generate(func(enc []byte) {
 		dec, ok := <-ext.Dec
 		if !ok {
diff --git a/riscv64/riscv64asm/ext_test.go b/riscv64/riscv64asm/ext_test.go
index 556cd01..d5753f9 100644
--- a/riscv64/riscv64asm/ext_test.go
+++ b/riscv64/riscv64asm/ext_test.go
@@ -122,8 +122,13 @@
 
 		errors = make([]string, 0, 100) // Sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
 
 	generate(func(enc []byte) {
diff --git a/x86/x86asm/ext_test.go b/x86/x86asm/ext_test.go
index 2e31dd3..beb527b 100644
--- a/x86/x86asm/ext_test.go
+++ b/x86/x86asm/ext_test.go
@@ -134,9 +134,15 @@
 
 		errors = make([]string, 0, 100) // sampled errors, at most cap
 	)
+
 	go func() {
-		errc <- extdis(ext)
+		err := extdis(ext)
+		if err != nil {
+			close(ext.Dec)
+		}
+		errc <- err
 	}()
+
 	generate(func(enc []byte) {
 		dec, ok := <-ext.Dec
 		if !ok {