Closed
Description
I was thinking some more about the examples in #14210. Here's a more realistic false-negative example that does "follow the rules", but still manages to leak a Go pointer into C undetected. It's not unlike what you might find in a program using, say, the SDL API.
It doesn't do any iffy casting in C, and its only iffy casting in Go is due to language support - this is exactly the code you end up writing if you have to deal with a C API with unions.
package main
/*
typedef enum {
DIRECT,
INDIRECT,
} kind;
typedef struct {
kind k;
} header;
typedef struct {
header hdr;
int payload;
} direct;
typedef struct {
header hdr;
int *payload;
} indirect;
typedef union {
header hdr;
direct d;
indirect i;
} either;
int get_payload(either *e) {
switch (e->hdr.k) {
case DIRECT:
return e->d.payload;
case INDIRECT:
return *(e->i.payload);
default:
return -1;
}
}
*/
import "C"
import (
"fmt"
"unsafe"
)
func main() {
var escapee C.int = 42
i := C.indirect{
hdr: C.header{k: C.INDIRECT},
payload: &escapee,
}
escaped := C.get_payload((*C.either)(unsafe.Pointer(&i)))
fmt.Println(escaped)
}
With go version go1.6.1 linux/amd64, this program outputs 42
and exits with code 0. It should instead panic with a cgo pointer violation.