Files
codeql/go/ql/test/query-tests/InconsistentCode/UnhandledCloseWritableHandle/tests.go
2023-02-06 08:47:47 +00:00

131 lines
3.0 KiB
Go

package test
import (
"log"
"os"
)
func openFileWrite(filename string) (*os.File, error) {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
return f, err
}
func openFileRead(filename string) (*os.File, error) {
return os.OpenFile(filename, os.O_RDONLY|os.O_CREATE, 0666)
}
func openFileReadWrite(filename string) (*os.File, error) {
return os.OpenFile(filename, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666)
}
func closeFileDeferred(f *os.File) {
defer f.Close() // NOT OK, if `f` is writable
}
func closeFileDeferredIndirect(f *os.File) {
var cont = func() {
f.Close() // NOT OK, if `f` is writable
}
defer cont()
}
func closeFileDeferredIndirectReturn(f *os.File) {
var cont = func() error {
return f.Close() // OK, because this function returns the error
}
// different (more general) problem: deferred error
defer cont()
}
func deferredCalls() {
if f, err := openFileWrite("foo.txt"); err != nil {
closeFileDeferred(f) // NOT OK
closeFileDeferredIndirect(f) // NOT OK
}
if f, err := openFileRead("foo.txt"); err != nil {
closeFileDeferred(f) // OK
closeFileDeferredIndirect(f) // OK
}
if f, err := openFileReadWrite("foo.txt"); err != nil {
closeFileDeferred(f) // NOT OK
closeFileDeferredIndirect(f) // NOT OK
}
}
func notDeferred() {
if f, err := openFileWrite("foo.txt"); err != nil {
// the handle is write-only and we don't check if `Close` succeeds
f.Close() // NOT OK
}
if f, err := openFileRead("foo.txt"); err != nil {
// the handle is read-only, so this is ok
f.Close() // OK
}
if f, err := openFileReadWrite("foo.txt"); err != nil {
// the handle is read-write and we don't check if `Close` succeeds
f.Close() // NOT OK
}
}
func foo() error {
if f, err := openFileWrite("foo.txt"); err != nil {
// the result of the call to `Close` is returned to the caller
return f.Close() // OK
}
return nil
}
func isSyncedFirst() {
if f, err := openFileWrite("foo.txt"); err != nil {
// we have a call to `Sync` and check whether it was successful before proceeding
if err := f.Sync(); err != nil {
f.Close() // OK
}
f.Close() // OK
}
}
func deferredCloseWithSync() {
if f, err := openFileWrite("foo.txt"); err != nil {
// a call to `Close` is deferred, but we have a call to `Sync` later which
// precedes the call to `Close` during execution
defer f.Close() // OK
if err := f.Sync(); err != nil {
log.Fatal(err)
}
}
}
func deferredCloseWithSyncEarlyReturn(n int) {
if f, err := openFileWrite("foo.txt"); err != nil {
// a call to `Close` is deferred
defer f.Close() // NOT OK
if n > 100 {
return
}
// we have a call to `Sync` here, but it might not get executed if n <= 100
if err := f.Sync(); err != nil {
log.Fatal(err)
}
}
}
func unhandledSync() {
if f, err := openFileWrite("foo.txt"); err != nil {
// we have a call to `Sync` which precedes the call to `Close`, but there is no check
// to see if `Sync` may have failed
f.Sync()
f.Close() // NOT OK
}
}