From 419429c62a4c3933f18c6af3d06161e2c4504331 Mon Sep 17 00:00:00 2001 From: Brian Stark Date: Mon, 1 Apr 2024 15:11:47 +0000 Subject: [PATCH 1/2] Prevent file handles from leaking on failed open. Since the webcam open function only returns the open fh on success, we need to close the FH ourselves in the event that the subsequent tests fail. --- webcam.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/webcam.go b/webcam.go index e008410..5fb394d 100644 --- a/webcam.go +++ b/webcam.go @@ -34,15 +34,25 @@ type Control struct { // Open a webcam with a given path // Checks if device is a v4l2 device and if it is // capable to stream video -func Open(path string) (*Webcam, error) { +func Open(path string) (w *Webcam, err error) { + w = nil + err = nil handle, err := unix.Open(path, unix.O_RDONLY|unix.O_NONBLOCK, 0666) if err != nil { - return nil, err + return } if handle < 0 { - return nil, fmt.Errorf("failed to open %v", path) + err = fmt.Errorf("failed to open %v", path) + return } + // At this point the handle is valid and must be return or closed + defer func() { + if err != nil { + // Since the handle is not returned on error we must close it or leak + unix.Close(handle) + } + }() fd := uintptr(handle) supportsVideoCapture, supportsVideoStreaming, err := checkCapabilities(fd) @@ -52,18 +62,20 @@ func Open(path string) (*Webcam, error) { } if !supportsVideoCapture { - return nil, errors.New("Not a video capture device") + err = errors.New("Not a video capture device") + return } if !supportsVideoStreaming { - return nil, errors.New("Device does not support the streaming I/O method") + err = errors.New("Device does not support the streaming I/O method") + return } - w := new(Webcam) + w = new(Webcam) w.fd = fd w.bufcount = 256 w.pollFds = []unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN}} - return w, nil + return } // Returns image formats supported by the device alongside with From 45143599de0c28d233470be14baa41037e7d95d6 Mon Sep 17 00:00:00 2001 From: Brian Stark Date: Mon, 1 Apr 2024 15:56:55 +0000 Subject: [PATCH 2/2] Moved to using bool to check success. --- webcam.go | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/webcam.go b/webcam.go index 5fb394d..66f236a 100644 --- a/webcam.go +++ b/webcam.go @@ -34,21 +34,18 @@ type Control struct { // Open a webcam with a given path // Checks if device is a v4l2 device and if it is // capable to stream video -func Open(path string) (w *Webcam, err error) { - w = nil - err = nil - +func Open(path string) (*Webcam, error) { handle, err := unix.Open(path, unix.O_RDONLY|unix.O_NONBLOCK, 0666) if err != nil { - return + return nil, err } if handle < 0 { - err = fmt.Errorf("failed to open %v", path) - return + return nil, fmt.Errorf("failed to open %v", path) } // At this point the handle is valid and must be return or closed + success := false // If this is not set true prior to function exit we assume error and close the handle defer func() { - if err != nil { + if !success { // Since the handle is not returned on error we must close it or leak unix.Close(handle) } @@ -62,20 +59,19 @@ func Open(path string) (w *Webcam, err error) { } if !supportsVideoCapture { - err = errors.New("Not a video capture device") - return + return nil, errors.New("Not a video capture device") } if !supportsVideoStreaming { - err = errors.New("Device does not support the streaming I/O method") - return + return nil, errors.New("Device does not support the streaming I/O method") } - w = new(Webcam) + w := new(Webcam) w.fd = fd w.bufcount = 256 w.pollFds = []unix.PollFd{{Fd: int32(fd), Events: unix.POLLIN}} - return + success = true + return w, nil } // Returns image formats supported by the device alongside with