uilive icon indicating copy to clipboard operation
uilive copied to clipboard

Syscall in getTermSize() corrupts package variable of a different library

Open VoIdemar opened this issue 4 years ago • 0 comments

Hi.

I am developing a CLI application which uses uilive v0.0.4 to output execution statistics to the console at runtime. Everything was fine until I decided to use sniper as a key-value storage for my app. It turned out that one of the sniper package variables got corrupted (changes it's value from 12 to 0) after calling uilive.New(). Without calling uilive.New() sniper works perfectly fine.

I traced the issue down to the IOCTL syscall in getTermSize() function in terminal_size.go:

//...
var sz windowSize

func getTermSize() (int, int) {
       //...
       // `sniper` package variable is fine here
	_, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
		out.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))
        // `sniper` package variable is reset to 0 
	return int(sz.cols), int(sz.rows)
}Ubuntu 20.04 LTS x64

I am not sure what goes wrong exactly, but it looks like using an unsafe.Pointer to the sz package variable somehow messes up the memory contents. I can't say if any other package variables are affected.

I managed to fix the issue by simply moving package variables from terminal_size.go into the getTermSize() function body, making them local (and they kinda should be local, there are no usages of them outside of terminal_size.go):

// +build !windows

package uilive

import (
	"os"
	"runtime"
	"syscall"
	"unsafe"
)

type windowSize struct {
	rows    uint16
	cols    uint16
}

func getTermSize() (int, int) {
	var (
		out *os.File
		err error
		sz  windowSize
	)
	if runtime.GOOS == "openbsd" {
		out, err = os.OpenFile("/dev/tty", os.O_RDWR, 0)
		if err != nil {
			return 0, 0
		}
	} else {
		out, err = os.OpenFile("/dev/tty", os.O_WRONLY, 0)
		if err != nil {
			return 0, 0
		}
	}
	_, _, _ = syscall.Syscall(syscall.SYS_IOCTL,
		out.Fd(), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&sz)))
	return int(sz.cols), int(sz.rows)
}

What do you think? Please help me out.

Env specs:

OS Ubuntu 20.04 LTS x64
Kernel 5.7.7-050707-generic
Go 1.15.7

PR: #39

P.S.: big thanks for the library, it's awesome :)

VoIdemar avatar Sep 10 '21 11:09 VoIdemar