2017-04-24 1 views
1

AWS S3에서 GZIP 파일을 읽는 데 문제가 있습니다. 간단한 코드 만 있고 오류 panic: runtime error: invalid memory address or nil pointer dereference이 표시됩니다. 그러나 여전히 문제를 찾기가 어렵습니다.Golang IO 읽기 파일의 잘못된 메모리 주소

오류 메시지는 gzip.NewReader...입니다. 왜 golang이보고 해 주십니까? 어떻게 해결할 수 있을까요?

goroutine 1 [running]: 
github.com/hensg/pushego/aws.GetGZIPProductsDump(0x7ffead44098f, 0xc, 0x7ffead44099f, 0x2f, 0x0, 0xc420190580, 0x0, 0x0) 
     /home/henrique/go/src/github.com/hensg/pushego/aws/s3.go:47 +0x2e7 
main.main() 
     /home/henrique/go/src/github.com/hensg/pushego/pushego.go:28 +0x249 

주 코드 (pushego.go)

package main 

import (
    "bufio" 
    "flag" 
    "log" 
    "os" 
    "time" 

    "github.com/hensg/pushego/aws" 
) 

func init() { 
    log.SetOutput(os.Stdout) 
} 

func main() { 
    log.Println("Starting...") 

    var bucket, key string 
    var timeout time.Duration 

    flag.StringVar(&bucket, "b", "", "Bucket name") 
    flag.StringVar(&key, "k", "", "Object key name") 
    flag.DurationVar(&timeout, "d", 0, "Download timeout") 
    flag.Parse() 

    gzipReader, err := aws.GetGZIPDump(bucket, key, timeout) // line 28 
    if err != nil { 
     log.Fatal("Failed to create GZIP reader") 
    } 
    defer gzipReader.Close() 

    scanner := bufio.NewScanner(gzipReader) 
    for scanner.Scan() { 
     log.Printf("Read: %s\n", scanner.Text()) 
    } 

    log.Printf("Successfully download file from %s/%s\n", bucket, key) 
} 

AWS 코드 (AWS/s3.go)

package aws 

import (
    "compress/gzip" 
    "context" 
    "log" 
    "time" 

    "github.com/aws/aws-sdk-go/aws" 
    "github.com/aws/aws-sdk-go/aws/awserr" 
    "github.com/aws/aws-sdk-go/aws/request" 
    "github.com/aws/aws-sdk-go/aws/session" 
    "github.com/aws/aws-sdk-go/service/s3" 
) 

func GetGZIPProductsDump(bucket, key string, timeout time.Duration) (*gzip.Reader, error) { 
    sess := session.Must(session.NewSession()) 
    svc := s3.New(sess) 

    // Create a context with a timeout that will abort the download if it takes 
    // more than the passed in timeout. 
    ctx := context.Background() 
    var cancelFn func() 
    if timeout > 0 { 
     ctx, cancelFn = context.WithTimeout(ctx, timeout) 
    } 
    // Ensure the context is canceled to prevent leaking. 
    // See context package for more information, https://golang.org/pkg/context/ 
    defer cancelFn() 

    // Uploads the object to S3. The Context will interrupt the request if the 
    // timeout expires. 
    resp, err := svc.GetObjectWithContext(ctx, &s3.GetObjectInput{ 
     Bucket: aws.String(bucket), 
     Key: aws.String(key), 
    }) 
    if err != nil { 
     if aerr, ok := err.(awserr.Error); ok && aerr.Code() == request.CanceledErrorCode { 
      // If the SDK can determine the request or retry delay was canceled 
      // by a context the CanceledErrorCode error code will be returned. 
      log.Fatal("Download canceled due to timeout, %v\n", err) 
     } else { 
      log.Fatal("Failed to download object, %v\n", err) 
     } 
    } 

    return gzip.NewReader(resp.Body) // line 47 
} 
+0

@Flimzy 의견을 포함한 전체 코드를 추가했습니다. 아니, 다른 어떤 진술도 없다. 오류 검사 후'defer gzipReader.Close()'를 추가하려고했지만 여전히 작동하지 않습니다. –

+0

@Flimzy 내 잘못입니다. 문제가되는 줄은'gzip.NewReader (...)'라고했습니다. 지연 시키려고했지만 여전히 작동하지 않습니다. –

+0

첫 번째 코드 조각 끝에'// line 28 '의 의미는 무엇입니까? – Flimzy

답변

0

문제가 상기 defer cancelFn()와 관련된 현재 해당 FUNC timeout이 0이면 설정되지 않습니다. 이로 인해 널 포인터가있는 패닉이 발생하므로 이전 if 문 내에서 defer을 이동해야합니다. b 그것이 사용되어야 할 때가 유일한 시점입니다. aws/s3.go의 코드는 다음과 같아야합니다.

... 
// Create a context with a timeout that will abort the download if it takes 
// more than the passed in timeout. 
ctx := context.Background() 
var cancelFn func() 
if timeout > 0 { 
    ctx, cancelFn = context.WithTimeout(ctx, timeout) 
    // Ensure the context is canceled to prevent leaking. 
    // See context package for more information, https://golang.org/pkg/context/ 
    defer cancelFn() 
} 
... 
관련 문제