2013-04-29 8 views
44

Uruchamiając mój program, ona panikuje i zwraca następujące:Go: panika: Runtime error: nieprawidłowy adres pamięci lub zerowa wskaźnik nieprawidłowego

panic: runtime error: invalid memory address or nil pointer dereference 
[signal 0xb code=0x1 addr=0x38 pc=0x26df] 

goroutine 1 [running]: 
main.getBody(0x1cdcd4, 0xf800000004, 0x1f2b44, 0x23, 0xf84005c800, ...) 
     /Users/matt/Dropbox/code/go/scripts/cron/fido.go:65 +0x2bb 
main.getToken(0xf84005c7e0, 0x10) 
     /Users/matt/Dropbox/code/go/scripts/cron/fido.go:140 +0x156 
main.main() 
     /Users/matt/Dropbox/code/go/scripts/cron/fido.go:178 +0x61 

goroutine 2 [syscall]: 
created by runtime.main 
     /usr/local/Cellar/go/1.0.3/src/pkg/runtime/proc.c:221 

goroutine 3 [syscall]: 
syscall.Syscall6() 
     /usr/local/Cellar/go/1.0.3/src/pkg/syscall/asm_darwin_amd64.s:38 +0x5 
syscall.kevent(0x6, 0x0, 0x0, 0xf840085188, 0xa, ...) 
     /usr/local/Cellar/go/1.0.3/src/pkg/syscall/zsyscall_darwin_amd64.go:199 +0x88 
syscall.Kevent(0xf800000006, 0x0, 0x0, 0xf840085188, 0xa0000000a, ...) 
     /usr/local/Cellar/go/1.0.3/src/pkg/syscall/syscall_bsd.go:546 +0xa4 
net.(*pollster).WaitFD(0xf840085180, 0xf840059040, 0x0, 0x0, 0x0, ...) 
     /usr/local/Cellar/go/1.0.3/src/pkg/net/fd_darwin.go:96 +0x185 
net.(*pollServer).Run(0xf840059040, 0x0) 
     /usr/local/Cellar/go/1.0.3/src/pkg/net/fd.go:236 +0xe4 
created by net.newPollServer 
     /usr/local/Cellar/go/1.0.3/src/pkg/net/newpollserver.go:35 +0x382 

Szukałem w odpowiedziach inni mieli do tego samego wyjątek, ale nie widać nic prostego (np. nieobsługiwany błąd).

Używam go na komputerze, który nie ma dostępu do serwerów API wymienionych w kodzie, ale miałem nadzieję, że zwróci odpowiedni błąd (jak próbowałem złapać tego rodzaju błędy).

package main 

/* 
Fido fetches the list of public images from the Glance server, captures the IDs of images with 'status': 'active' and then queues the images for pre-fetching with the Glance CLI utility `glance-cache-manage`. Once the images are added to the queue, `glance-cache-prefetcher` is called to actively fetch the queued images into the local compute nodes' image cache. 

See http://docs.openstack.org/developer/glance/cache.html for further details on the Glance image cache. 
*/ 

import (
    "bytes" 
    "encoding/json" 
    "fmt" 
    "io/ioutil" 
    /* 
     "log" 
     "log/syslog" 
    */ 
    "net/http" 
    "os" 
    "os/exec" 
) 

func prefetchImages() error { 

    cmd := exec.Command("glance-cache-prefetcher") 
    err := cmd.Run() 

    if err != nil { 
     return fmt.Errorf("glance-cache-prefetcher failed to execute properly: %v", err) 
    } 

    return nil 
} 

func queueImages(hostname string, imageList []string) error { 

    for _, image := range imageList { 
     cmd := exec.Command("glance-cache-manage", "--host=", hostname, "queue-image", image) 
     err := cmd.Run() 

     if err != nil { 
      return fmt.Errorf("glance-cache-manage failed to execute properly: %v", err) 
     } else { 
      fmt.Printf("Image %s queued", image) 
     } 
    } 

    return nil 
} 

func getBody(method string, url string, headers map[string]string, body []byte) ([]byte, error) { 

    client := &http.Client{} 
    req, err := http.NewRequest(method, url, bytes.NewReader(body)) 

    if err != nil { 
     return nil, err 
    } 

    for key, value := range headers { 
     req.Header.Add(key, value) 
    } 

    res, err := client.Do(req) 
    defer res.Body.Close() 

    if err != nil { 
     return nil, err 
    } 

    var bodyBytes []byte 

    if res.StatusCode == 200 { 
     bodyBytes, err = ioutil.ReadAll(res.Body) 
    } else if err != nil { 
     return nil, err 
    } else { 
     return nil, fmt.Errorf("The remote end did not return a HTTP 200 (OK) response.") 
    } 

    return bodyBytes, nil 

} 

func getImages(authToken string) ([]string, error) { 

    type GlanceDetailResponse struct { 
     Images []struct { 
      Name string `json:"name"` 
      Status string `json:"status"` 
      ID  string `json:"id"` 
     } 
    } 

    method := "GET" 
    url := "http://192.168.1.2:9292/v1.1/images/detail" 
    headers := map[string]string{"X-Auth-Token": authToken} 

    bodyBytes, err := getBody(method, url, headers, nil) 

    if err != nil { 
     return nil, fmt.Errorf("unable to retrieve the response body from the Glance API server: %v", err) 
    } 

    var glance GlanceDetailResponse 
    err = json.Unmarshal(bodyBytes, &glance) 

    if err != nil { 
     return nil, fmt.Errorf("unable to parse the JSON response:", err) 
    } 

    imageList := make([]string, 10) 

    for _, image := range glance.Images { 
     if image.Status == "active" { 
      imageList = append(imageList, image.ID) 
     } 
    } 

    return imageList, nil 

} 

func getToken() (string, error) { 

    type TokenResponse struct { 
     Auth []struct { 
      Token struct { 
       Expires string `json:"expires"` 
       ID  string `json:"id"` 
      } 
     } 
    } 

    method := "POST" 
    url := "http://192.168.1.2:5000/v2.0/tokens" 
    headers := map[string]string{"Content-type": "application/json"} 
    creds := []byte(`{"auth":{"passwordCredentials":{"username": "glance", "password":"<password>"}, "tenantId":"<tenantkeygoeshere>"}}`) 

    bodyBytes, err := getBody(method, url, headers, creds) 

    if err != nil { 
     return "", err 
    } 

    var keystone TokenResponse 
    err = json.Unmarshal(bodyBytes, &keystone) 

    if err != nil { 
     return "", err 
    } 

    authToken := string((keystone.Auth[0].Token.ID)) 

    return authToken, nil 
} 

func main() { 

    /* 
     slog, err := syslog.New(syslog.LOG_ERR, "[fido]") 

     if err != nil { 
      log.Fatalf("unable to connect to syslog: %v", err) 
      os.Exit(1) 
     } else { 
      defer slog.Close() 
     } 
    */ 

    hostname, err := os.Hostname() 

    if err != nil { 
     // slog.Err("Hostname not captured") 
     os.Exit(1) 
    } 

    authToken, err := getToken() 

    if err != nil { 
     // slog.Err("The authentication token from the Glance API server was not retrieved") 
     os.Exit(1) 
    } 

    imageList, err := getImages(authToken) 

    err = queueImages(hostname, imageList) 

    if err != nil { 
     // slog.Err("Could not queue the images for pre-fetching") 
     os.Exit(1) 
    } 

    err = prefetchImages() 

    if err != nil { 
     // slog.Err("Could not queue the images for pre-fetching") 
     os.Exit(1) 
    } 

    return 
} 

Odpowiedz

57

Zgodnie z docs dla func (*Client) Do:

"An error is returned if caused by client policy (such as CheckRedirect), or if there was an HTTP protocol error. A non-2xx response doesn't cause an error.

When err is nil, resp always contains a non-nil resp.Body."

Wtedy patrząc na ten kod:

res, err := client.Do(req) 
defer res.Body.Close() 

if err != nil { 
    return nil, err 
} 

Zgaduję, że err nie jest nil. Masz dostęp do metody .Close() na res.Body, zanim sprawdzisz, czy jest err.

Tylko defer wywołuje wywołanie funkcji. Pole i metoda są dostępne natychmiast.


Zamiast tego spróbuj natychmiast sprawdzić błąd.

res, err := client.Do(req) 

if err != nil { 
    return nil, err 
} 
defer res.Body.Close() 
+0

Dzięki - poprawione. – elithrar

+0

Idealnie! przesunięcie opóźnienia po sprawdzeniu błędu rozwiązało to. – Melvin

+0

if err! = Nil, res.Body = nil, dlaczego res.Body.Close() można wywołać? – oohcode

4

NIL wskaźnik nieprawidłowego jest w linii 65, która jest Defer w

res, err := client.Do(req) 
defer res.Body.Close() 

if err != nil { 
    return nil, err 
} 

Jeśli err! = Nil res == nil i res.Body panikuje. Uchwyt err przed odłożeniem res.Body.Close().

-1

dla mnie jednym z rozwiązań tego problemu było dodanie sql.Open ... sslmode = wyłączanie

Powiązane problemy