mirror of
				https://github.com/go-delve/delve.git
				synced 2025-11-01 03:42:59 +08:00 
			
		
		
		
	terminal: bugfix: deref of nil SelectedGoroutine switching goroutines (#829)
If CurrentThread isn't running a goroutine SelectedGoroutine can be nil, do not blindly dereference it. Fixes #827
This commit is contained in:
		 Alessandro Arzilli
					Alessandro Arzilli
				
			
				
					committed by
					
						 Derek Parker
						Derek Parker
					
				
			
			
				
	
			
			
			 Derek Parker
						Derek Parker
					
				
			
						parent
						
							f6091694b6
						
					
				
				
					commit
					98a4ff7a9f
				
			
							
								
								
									
										23
									
								
								_fixtures/notify-v2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								_fixtures/notify-v2.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	http.HandleFunc("/test", func(w http.ResponseWriter, req *http.Request) { | ||||
| 		go func() { | ||||
| 			// I know this is wrong, it is just to simulate a deadlocked goroutine | ||||
| 			fmt.Println("locking...") | ||||
| 			mtx := &sync.Mutex{} | ||||
| 			mtx.Lock() | ||||
| 			mtx.Lock() | ||||
| 			fmt.Println("will never print this") | ||||
| 		}() | ||||
| 	}) | ||||
|  | ||||
| 	log.Fatalln(http.ListenAndServe("127.0.0.1:8888", nil)) | ||||
| } | ||||
| @ -473,6 +473,13 @@ func goroutines(t *Term, ctx callContext, argstr string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func selectedGID(state *api.DebuggerState) int { | ||||
| 	if state.SelectedGoroutine == nil { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return state.SelectedGoroutine.ID | ||||
| } | ||||
|  | ||||
| func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error { | ||||
| 	args := strings.SplitN(argstr, " ", 2) | ||||
|  | ||||
| @ -505,7 +512,7 @@ func (c *Commands) goroutine(t *Term, ctx callContext, argstr string) error { | ||||
| 			return err | ||||
| 		} | ||||
|  | ||||
| 		fmt.Printf("Switched from %d to %d (thread %d)\n", oldState.SelectedGoroutine.ID, gid, newState.CurrentThread.ID) | ||||
| 		fmt.Printf("Switched from %d to %d (thread %d)\n", selectedGID(oldState), gid, newState.CurrentThread.ID) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
|  | ||||
| @ -5,12 +5,14 @@ import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/derekparker/delve/pkg/proc/test" | ||||
| 	"github.com/derekparker/delve/service" | ||||
| @ -38,6 +40,8 @@ type FakeTerminal struct { | ||||
| 	t testing.TB | ||||
| } | ||||
|  | ||||
| const logCommandOutput = false | ||||
|  | ||||
| func (ft *FakeTerminal) Exec(cmdstr string) (outstr string, err error) { | ||||
| 	outfh, err := ioutil.TempFile("", "cmdtestout") | ||||
| 	if err != nil { | ||||
| @ -54,6 +58,9 @@ func (ft *FakeTerminal) Exec(cmdstr string) (outstr string, err error) { | ||||
| 			ft.t.Fatalf("could not read temporary output file: %v", err) | ||||
| 		} | ||||
| 		outstr = string(outbs) | ||||
| 		if logCommandOutput { | ||||
| 			ft.t.Logf("command %q -> %q", cmdstr, outstr) | ||||
| 		} | ||||
| 		os.Remove(outfh.Name()) | ||||
| 	}() | ||||
| 	err = ft.cmds.Call(cmdstr, ft.Term) | ||||
| @ -581,3 +588,18 @@ func TestCheckpoints(t *testing.T) { | ||||
| 		listIsAt(t, term, "restart c1", 16, -1, -1) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestIssue827(t *testing.T) { | ||||
| 	// switching goroutines when the current thread isn't running any goroutine | ||||
| 	// causes nil pointer dereference. | ||||
| 	withTestTerminal("notify-v2", t, func(term *FakeTerminal) { | ||||
| 		go func() { | ||||
| 			time.Sleep(1 * time.Second) | ||||
| 			http.Get("http://127.0.0.1:8888/test") | ||||
| 			time.Sleep(1 * time.Second) | ||||
| 			term.client.Halt() | ||||
| 		}() | ||||
| 		term.MustExec("continue") | ||||
| 		term.MustExec("goroutine 1") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user