SSA IR Primitives Alloc BinOp Builtin Call ChangeInterface ChangeType Const Convert DebugRef Defer Extract Field FieldAddr FreeVar Function Global Go If Index IndexAddr Jump Lookup MakeChan MakeClosure MakeInterface MakeMap MakeSlice MapUpdate NamedConst Next Panic Parameter Phi Range Return RunDefers Select Send Slice Store Type TypeAssert UnOp
safesql func main() { // Open database. db, err := sql.Open("postgres", "dbname=db0") if err != nil { log.Fatal(err) } defer db.Close() // Retrieve color from CLI args. color := flag.Arg(0) // Execute query. db.Query("SELECT FROM widgets WHERE color = '" + color + "'") }
safesql func main() { // Open database. db, err := sql.Open("postgres", "dbname=db0") if err != nil { log.Fatal(err) } defer db.Close() // Retrieve color from CLI args. color := flag.Arg(0) // Execute query. db.Query("SELECT FROM widgets WHERE color = '" + color + "'") } User Input
safesql $ safesql . Found 1 potentially unsafe SQL statements: - main.go:13:10 Please ensure that all SQL queries you use are compile-time constants. You should always use parameterized queries or prepared statements instead of building queries from strings.
oracle • What code calls a function • What code is called by a function • Trace possible paths to a function call from main() • Determine what implements an interface • Find who sends to & receives from a channel • Determine possible values of a pointer • Find other identifiers that refer to the same value
type I interface { Foo() } type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} func doSomething(condition bool) { var x I = &T{} x.Foo() if condition { x = &V{} } x.Foo() }
type I interface { Foo() } type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} func doSomething(condition bool) { var x I = &T{} x.Foo() if condition { x = &V{} } x.Foo() }
type I interface { Foo() } type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} func doSomething(condition bool) { var x I = &T{} if condition { x = &V{} x.Foo() } }
type I interface { Foo() } type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} func doSomething(condition bool) { var x I = &T{} if condition { x = &V{} x.Foo() } }
type I interface { Foo() } type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} func doSomething(condition bool) { var x I = &T{} if condition { x = &V{} x.Foo() } }
type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} type I interface { Foo() } func doSomething(cond bool) { var x I = &T{} if cond { x = &V{} } fmt.Printf("x is %T\n", x) }
type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} type I interface { Foo() } func doSomething(cond bool) { var x I = &T{} if cond { x = &V{} } fmt.Printf("x is %T\n", x) }
$ oracle -pos main.go:#168 pointsto main.go main.go:21:6: this I may contain these dynamic types: main.go:8:6: *T, may point to: main.go:21:14: complit
type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} type I interface { Foo() } func doSomething(cond bool) { var x I = &T{} if cond { x = &V{} } fmt.Printf("x is %T\n", x) }
$ oracle -pos main.go:#206 pointsto main.go main.go:24:3: this I may contain these dynamic types: main.go:12:6: *V, may point to: main.go:24:9: complit
type T struct{} func (*T) Foo() {} type V struct{} func (*V) Foo() {} type I interface { Foo() } func doSomething(cond bool) { var x I = &T{} if cond { x = &V{} } fmt.Printf("x is %T\n", x) }
$ oracle -pos main.go:#244 pointsto main.go main.go:27:26: this I may contain these dynamic types: main.go:8:6: *T, may point to: main.go:21:14: complit main.go:12:6: *V, may point to: main.go:24:9: complit
gorename • Safely renames identifiers • Renames the declaration as well as references. • Even works across packages in GOPATH • Just uses go/types but it’s still cool • Intelligently prevents ambiguity and shadowing conflicts.
gorename mypkg.go:2:6: renaming this var "x" to "y" mypkg.go:4:3: would cause this reference to become shadowed mypkg.go:5:5: by this intervening var definition Shadowing Conflict