I have a go program that modifies my configuration file. I am trying to create a filelock from within the main() function, but it is throwing a panic: runtime error: invalid memory address or nil pointer dereference
error. Without the lock, the program is working fine as expected. The piece of code that throws exception is
lockProgram, err := os.Create("/var/.daemon.lock")
defer lockProgram.Close()
CheckForError(err)
GetLock(lockProgram, syscall.LOCK_EX)
defer UngetLock(lockProgram)
//This is in a separate package
func CheckForError(e error) {
if e != nil {
Error.Println(e)
panic(e)
}
}
func GetLock(file *os.File, locktype int ) {
fmt.Println("Acquiring lock on ", file.Name())
syscall.Flock(int(file.Fd()), locktype)
fmt.Println("Acquired filelock on ", file.Name())
}
func UngetLock(file *os.File) {
syscall.Flock(int(file.Fd()), syscall.LOCK_UN);
}
This same flock
is working when I call it on my configuration file, but from a different package, not main package, but throws the same error when I try to put lock from within the main package. Please help me in finding out what am I doing wrong here.
When an error occurs while creating the lock, lockProgram
will be nil
. This will cause the subsequent (deferred) call to lockProgram.Close()
to fail.
Note that when you're panicking (like in your CheckForError
function), deferred method calls will still be executed. This is explained in detail in this blog article (emphasis mine):
Panic is a built-in function that stops the ordinary flow of control and begins panicking. When the function F calls panic, execution of F stops, any deferred functions in F are executed normally, and then F returns to its caller. To the caller, F then behaves like a call to panic. The process continues up the stack until all functions in the current goroutine have returned, at which point the program crashes.
Solution: Check for errors first, and then defer the Close()
call:
lockProgram, err := os.Create("/var/.daemon.lock")
CheckForError(err)
defer lockProgram.Close()