2013-04-29 55 views
44

当运行我的围棋程序,它恐慌和返回如下:转到:恐慌:运行时错误:无效的内存地址或零指针引用

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 

我已经看过了回应别人有相同的异常,但看不到任何简单的东西(即未处理的错误)。

我在没有访问代码中列出的API服务器的机器上运行它,但我希望它会返回一个适当的错误(因为我试图捕获那种类型的错误)。

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 
} 

回答

57

根据该文档为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."

然后看着这个代码:

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

if err != nil { 
    return nil, err 
} 

我猜errnil。您正在访问的res.Body.Close()方法,你检查的err之前。

defer只是推迟函数调用。该字段和方法被立即访问。


因此,请尝试立即检查错误。

res, err := client.Do(req) 

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

感谢 - 即纠正它。 – elithrar 2013-04-29 14:35:28

+0

完美!错误检查解决后移动延迟。 – Melvin 2016-03-30 07:40:17

+0

如果犯错!=零,res.Body =零,为什么res.Body.Close()可以打电话? – oohcode 2017-07-04 03:23:54

4

的零指针引用是在第65行,其是在

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

if err != nil { 
    return nil, err 
} 

的延迟如果ERR!=零然后RES ==零和res.Body恐慌。 defering的res.Body.Close之前 手柄ERR()。

-1

对我来说这个问题的一个解决方案是在sql.Open ... sslmode =添加禁用

相关问题