Unable check nil pointer

Hello, everyone!
I just got into programming.Now i can not check nil pointer and can not figure out why, plz help to take a look, thanks.

		//List instance tags
		for _, tag := range inst.Tags {
			v := "Null"
			if tag.Value == nil {
				fmt.Printf("%s is nil", *tag.Key)
				continue
			}
			if reflect.ValueOf(&tag.Value).IsNil() {
				fmt.Println("Nil")
			}

			if tag.Value != nil {
				v = *tag.Value
			}
			k := *tag.Key
			fmt.Println(k, v)
			switch k {
			case "Name":
				data.Name = &v
			case "Environment":
				data.Env = &v
			case "Service":
				data.Service = &v
			case "Role":
				data.Role = &v
			}

Output:
Name dev-jixxx
Environment DEV
IPv4 私有IP 172.31.23.xx
Dev
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x13778b4]

goroutine 1 [running]:
main.writeInstances()
/Users/jizheng/outsidegopath/aws_inventory/list_inventory.go:113 +0x6a4
main.main()
/Users/jizheng/outsidegopath/aws_inventory/list_inventory.go:169 +0x27
exit status 2

Hello. Can you provide minimal code for reproducing the behaviour?
Also on which exactly line of the code above you getting panic?

From documentation to IsNil/0:

IsNil reports whether its argument v is nil. The argument must be a chan, func, interface, map, pointer, or slice value; if it is not, IsNil panics. Note that IsNil is not always equivalent to a regular comparison with nil in Go. For example, if v was created by calling ValueOf with an uninitialized interface variable i, i==nil will be true but v.IsNil will panic as v will be the zero Value.

Hi! Here is the complete code below. Forgive me that i don’t know how to compose type. :joy:
Some "*tag.Value"s are nil.

package main

import (
	"database/sql"
	"fmt"
	"log"
	"reflect"

	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/ec2"
	_ "github.com/go-sql-driver/mysql" //_ stands for only importing init func in the package
)

var region = "us-west-2"

type ec2Resources struct {
	Name         *string
	Env          *string
	Service      *string
	Role         *string
	InstanceType *string
}

func writeInstances() {
	//Create a new session
	sess := session.Must(session.NewSession())
	svc := ec2.New(sess)

	//Describe all instances
	result, err := svc.DescribeInstances(nil)
	if err != nil {
		panic(err)
	}

	var data ec2Resources

	for idx, _ := range result.Reservations {
		for _, inst := range result.Reservations[idx].Instances {

			data.InstanceType = inst.InstanceType

			//List instance tags
			for _, tag := range inst.Tags {
				v := "Null"
				if tag.Value == nil {
					fmt.Printf("%s is nil", *tag.Key)
					continue
				}
				if reflect.ValueOf(&tag.Value).IsNil() {
					fmt.Println("Nil")
				}

				if tag.Value != nil {
					v = *tag.Value
				}
				k := *tag.Key
				fmt.Println(k, v)
				switch k {
				case "Name":
					data.Name = &v
				case "Environment":
					data.Env = &v
				case "Service":
					data.Service = &v
				case "Role":
					data.Role = &v
				}

				// fmt.Println(reflect.TypeOf(*tag))
				// if *tag.Key == "Name" {
				// 	//fmt.Printf("Env is %s\n", *tag.Value)
				// 	if tag.Value != nil {
				// 		data.Name = tag.Value
				// 		fmt.Println("Name")
				// 	} else {
				// 		*data.Name = "Null"
				// 	}
				// } else if *tag.Key == "Environment" {
				// 	if tag.Value != nil {
				// 		data.Env = tag.Value
				// 		fmt.Println("Env")
				// 	} else {
				// 		*data.Env = "Null"
				// 	}
				// } else if *tag.Key == "Service" {
				// 	if tag.Value != nil {
				// 		data.Service = tag.Value
				// 	} else {
				// 		panic("errrrrrror")
				// 		*data.Service = "Null"
				// 	}
				// } else if *tag.Key == "Role" {
				// 	if tag.Value != nil {
				// 		data.Role = tag.Value
				// 	} else {
				// 		*data.Role = "Null"
				// 		fmt.Println("Role")
				// 		panic("NULL")
				// 	}
				// }
			}
			//Update first, if not exist, then try to insert.
			fmt.Println(reflect.TypeOf(*data.Role))
			sql := fmt.Sprintf(
				"UPDATE ec2 SET Environment = %s, Service = %s, Role = %s, InstanceType = %s",
				*data.Env,
				*data.Service,
				*data.Role,
				*data.InstanceType,
			)
			fmt.Println("update finish")
			log.Println("sql:", sql)
			result, err := db.Exec(sql)
			if err != nil {
				log.Println("Exec failed:", err, ";SQL:", sql)
				return
			}
			//c is number of affected rows.
			c, err := result.RowsAffected()
			if err != nil {
				log.Println("Rows affected failed:", err)
				return
			}
			//If affected rows num is 0, then INSERT.
			if c == 0 {
				sql := fmt.Sprintf(
					"INSERT INTO ec2(Name, Environment, Service, Role, InstanceType) VALUES ('%s', '%s', '%s', '%s', '%s')",
					*data.Name,
					*data.Env,
					*data.Service,
					*data.Role,
					*data.InstanceType,
				)
				log.Println("Not exist, try to insert.")
				_, err := db.Exec(sql)
				if err != nil {
					log.Println("Exec Failed", err, ";SQL:", sql)
				}

			}
		}
	}
}

var db *sql.DB
var err error

func connectDatabase() {
	db, err = sql.Open("mysql", "jizheng/password@xxx/mysql")
	//log.Fatal will terminate process immediately but panic will do until defer func finish.
	if err != nil {
		log.Fatal("Database connected failed!")
	}
	fmt.Println("Database connected.")
}

func main() {
	connectDatabase()
	writeInstances()
	db.Close()
}

Sorry i can not manage to provide minimal code to reproduce the error, so i put entire code in here. I will sincerely appreciate it if you can give me some advice!

This can never be nil, as tag.Value always has an address where it is stored.

Oh, but tag.Value can be nil, right ?

You get a panic on line 113 but what is

result, err := db.Exec(sql)

So I guess you have changed your program after you posted the listing. Which line is the panic on now?

Sorry, now it is 103
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x13778b4]

goroutine 1 [running]:
main.writeInstances()
/Users/jizheng/outsidegopath/aws_inventory/list_inventory.go:103 +0x6a4
main.main()
/Users/jizheng/outsidegopath/aws_inventory/list_inventory.go:159 +0x27
exit status 2

Could you put this line before line 103? It prints the value of data with types etc:

fmt.Printf("%#v\n", data)

And post here what it prints

Sorry man, my focus was completely wrong. At first i thought all ec2 have all the tag.Keys but not every key has a value. The panic is not because of the tag.Value but the tag.Key. Because some ec2 instances don’t have all the keys i specified, like an ec2 doesn’t have tag “Role”, so data.Role is nil. Thanks for you guys’ help!

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.