이동 : 패닉 : 런타임 오류 : 유효하지 않은 메모리 주소 또는 포인터 역 참조 없음
내 Go 프로그램을 실행할 때 패닉이 발생하고 다음을 반환합니다.
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
}
문서에 따르면 func (*Client) Do:
"클라이언트 정책 (예 : CheckRedirect)으로 인해 오류가 발생하거나 HTTP 프로토콜 오류가 발생한 경우 오류가 반환됩니다. 2xx가 아닌 응답은 오류를 일으키지 않습니다.
err이 nil이면 resp는 항상 nil이 아닌 resp.Body를 포함합니다. "
그런 다음이 코드를 살펴보십시오.
res, err := client.Do(req)
defer res.Body.Close()
if err != nil {
return nil, err
}
I'm guessing that err is not nil. You're accessing the .Close() method on res.Body before you check for the err.
The defer only defers the function call. The field and method are accessed immediately.
So instead, try checking the error immediately.
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
The nil pointer dereference is in line 65 which is the defer in
res, err := client.Do(req)
defer res.Body.Close()
if err != nil {
return nil, err
}
If err!= nil then res==nil and res.Body panics. Handle err before defering the res.Body.Close().
Since I got here with my problem I will add this answer although it is not exactly relevant to the original question. When you are implementing an interface make sure you do not forget to add the type pointer on your member function declarations. Example:
type AnimalSounder interface {
MakeNoise()
}
type Dog struct {
Name string
mean bool
BarkStrength int
}
func (dog *Dog) MakeNoise() {
//implementation
}
I forgot the *(dog Dog) part, I do not recommend it. Then you get into ugly trouble when calling MakeNoice on an AnimalSounder interface variable of type Dog.
for me one solution for this problem was to add in sql.Open ... sslmode=disable
'Program Club' 카테고리의 다른 글
| java : "최종"System.out, System.in 및 System.err? (0) | 2020.10.19 |
|---|---|
| SBT 0.13 프로젝트에서 메인 클래스를 설정하는 방법 (0) | 2020.10.19 |
| Django와 ReactJS-실제 사용 (0) | 2020.10.19 |
| Javascript의 sort ()는 어떻게 작동합니까? (0) | 2020.10.19 |
| 전체 파일 대신 한 줄을 git-checkout 할 수 있습니까? (0) | 2020.10.18 |