Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault when closing the client with server disconnected #567

Closed
cailloumajor opened this issue Mar 22, 2022 · 1 comment · Fixed by #562
Closed

Segmentation fault when closing the client with server disconnected #567

cailloumajor opened this issue Mar 22, 2022 · 1 comment · Fixed by #562

Comments

@cailloumajor
Copy link

Description

When the client is trying to reconnect to the server, closing it with Close or CloseWithContext method causes a segmentation fault.

I investigated and found that the connection (conn field of the Client struct) becomes nil in Dial method during the process of trying to reconnect:

opcua/client.go

Line 534 in 166c1c7

c.conn, err = d.Dial(ctx, c.endpointURL)

Later, closing the client causes c.conn.Close method to be called on a nil pointer:

opcua/client.go

Line 588 in 166c1c7

c.conn.Close()

This ends trying to dereference a nil pointer in the method:

opcua/uacp/conn.go

Lines 215 to 218 in 166c1c7

func (c *Conn) close() error {
debug.Printf("uacp %d: close", c.id)
return c.TCPConn.Close()
}

Reproduction

main.go:

package main

import (
	"context"
	"flag"
	"log"
	"os"
	"os/signal"

	"github.com/gopcua/opcua"
)

func main() {
	endpoint := flag.String("endpoint", "", "OPC-UA server endpoint URL")
	flag.Parse()
	client := opcua.NewClient(*endpoint)
	if err := client.Connect(context.Background()); err != nil {
		log.Fatalf("error connecting: %v", err)
	}
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, os.Interrupt)
	<-sc
	if err := client.CloseWithContext(context.Background()); err != nil {
		log.Printf("error closing: %v\n", err)
	}
}
  1. With an OPC-UA server ready to accept connections (anonymous auth and no message security), run the code in above main.go:
$ OPC_DEBUG=debug go run ./main.go -endpoint opc.tcp://172.17.0.3:4840
debug: uacp: connecting to opc.tcp://172.17.0.3:4840
debug: uacp 1: start HEL/ACK handshake
debug: uacp 1: sent HELF with 57 bytes
debug: uacp 1: recv ACKF with 28 bytes
debug: uacp 1: server has no chunk limit. Using 512
debug: uacp 1: server has no message size limit. Using 2097152
debug: uacp 1: recv &uacp.Acknowledge{Version:0x0, ReceiveBufSize:0xffff, SendBufSize:0xffff, MaxMessageSize:0x200000, MaxChunkCount:0x200}
debug: uasc 1/1: send *ua.OpenSecureChannelRequest with 132 bytes
debug: uacp 1: recv OPNF with 135 bytes
debug: uasc 1/1: recv OPNF with 135 bytes
debug: uasc 1/1: recv *ua.OpenSecureChannelResponse
debug: uasc 1/1: sending *ua.OpenSecureChannelResponse to handler
debug: uasc 1: received security token. channelID=1 tokenID=1 createdAt=2022-03-22T08:32:11Z lifetime=10m0s
debug: uasc 1: security token is refreshed at 2022-03-22T08:39:41Z (7m30s). channelID=1 tokenID=1
debug: uasc 1/2: send *ua.CreateSessionRequest with 264 bytes
debug: uacp 1: recv MSGF with 5487 bytes
debug: uasc 1/2: recv MSGF with 5487 bytes
debug: uasc 1: security token expires at 2022-03-22T08:44:41Z. channelID=1 tokenID=1
debug: uasc 1/2: recv *ua.CreateSessionResponse
debug: uasc 1/2: sending *ua.CreateSessionResponse to handler
debug: uasc 1/3: send *ua.ActivateSessionRequest with 146 bytes
debug: uacp 1: recv MSGF with 96 bytes
debug: uasc 1/3: recv MSGF with 96 bytes
debug: uasc 1/3: recv *ua.ActivateSessionResponse
debug: uasc 1/3: sending *ua.ActivateSessionResponse to handler
debug: client: monitor: start
debug: uasc 1/4: send *ua.ReadRequest with 111 bytes
debug: sub: pause
debug: uacp 1: recv MSGF with 142 bytes
debug: uasc 1/4: recv MSGF with 142 bytes
debug: uasc 1/4: recv *ua.ReadResponse
debug: uasc 1/4: sending *ua.ReadResponse to handler
  1. Now stop the OPC-UA server, causing the client to try to reconnect
debug: uasc 1: readChunk EOF
debug: client: monitor: disconnected
debug: client: monitor: auto-reconnecting
debug: client: monitor: action: createSecureChannel
debug: uacp 1: close
debug: sub: pause: pause
debug: uasc 1: Close()
debug: client: monitor: trying to recreate secure channel
debug: uacp: connecting to opc.tcp://172.17.0.3:4840
debug: client: monitor: trying to recreate secure channel
debug: uacp: connecting to opc.tcp://172.17.0.3:4840
  1. Hit Ctrl+C
^Cdebug: client: monitor: done
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x5820f6]

goroutine 1 [running]:
github.com/gopcua/opcua/uacp.(*Conn).Close(0xc0001fe0e0)
        /go/src/github.com/gopcua/opcua/uacp/conn.go:211 +0x36
github.com/gopcua/opcua.(*Client).CloseWithContext(0xc0001fe0e0, {0x6e1cb0, 0xc00001c0d8})
        /go/src/github.com/gopcua/opcua/client.go:588 +0x12a
main.main()
        /workspaces/gopcua-sigsev-repro/main.go:23 +0x16f
exit status 2
@cailloumajor
Copy link
Author

Thank you.
And sorry for the dup...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant