Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 25 additions & 31 deletions go/adbc/pkg/_tmpl/driver.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -230,30 +230,30 @@ func printLoggingHelp() {
}


// Allocate a new cgo.Handle and store its address in a heap-allocated
// uintptr_t. Experimentally, this was found to be necessary, else
// something (the Go runtime?) would corrupt (garbage-collect?) the
// handle.
// cgo.Handle is a uintptr integer (not a pointer). Packing it directly into
// a void* field is safe: the CGO checker only rejects Go heap pointers, and
// handle values (small non-zero integers from a global counter) never alias
// Go-allocated memory. The GC does not scan C-managed memory, so it will
// never misinterpret the stored integer as a live pointer. No C allocation
// is needed — the handle value itself fits in the pointer-sized field.
func createHandle(hndl cgo.Handle) unsafe.Pointer {
// uintptr_t* hptr = malloc(sizeof(uintptr_t));
hptr := (*C.uintptr_t)(C.calloc(C.sizeof_uintptr_t, C.size_t(1)))
// *hptr = (uintptr)hndl;
*hptr = C.uintptr_t(uintptr(hndl))
return unsafe.Pointer(hptr)
return unsafe.Pointer(uintptr(hndl))
}

func handleFromPtr(ptr unsafe.Pointer) cgo.Handle {
return cgo.Handle(uintptr(ptr))
}

func getFromHandle[T any](ptr unsafe.Pointer) *T {
// uintptr_t* hptr = (uintptr_t*)ptr;
hptr := (*C.uintptr_t)(ptr)
return cgo.Handle((uintptr)(*hptr)).Value().(*T)
return handleFromPtr(ptr).Value().(*T)
}

func exportStringOption(val string, out *C.char, length *C.size_t) C.AdbcStatusCode {
lenWithTerminator := C.size_t(len(val) + 1)
if lenWithTerminator <= *length {
sink := fromCArr[byte]((*byte)(unsafe.Pointer(out)), int(*length))
copy(sink, val)
sink[lenWithTerminator] = 0
sink[len(val)] = 0
}
*length = lenWithTerminator
return C.ADBC_STATUS_OK
Expand Down Expand Up @@ -417,17 +417,16 @@ func {{.Prefix}}ArrayStreamRelease(stream *C.struct_ArrowArrayStream) {
if stream == nil || stream.release != (*[0]byte)(C.{{.Prefix}}ArrayStreamRelease) || stream.private_data == nil {
return
}
h := (*(*cgo.Handle)(stream.private_data))
h := handleFromPtr(stream.private_data)
stream.private_data = nil

cStream := h.Value().(*cArrayStream)
h.Delete()
cStream.rdr.Release()
if cStream.adbcErr != nil {
C.{{.Prefix}}errRelease(cStream.adbcErr)
C.free(unsafe.Pointer(cStream.adbcErr))
}
C.free(unsafe.Pointer(stream.private_data))
stream.private_data = nil
h.Delete()
runtime.GC()
}

Expand Down Expand Up @@ -614,19 +613,16 @@ func {{.Prefix}}DatabaseRelease(db *C.struct_AdbcDatabase, err *C.struct_AdbcErr
if !checkDBAlloc(db, err, "AdbcDatabaseRelease") {
return C.ADBC_STATUS_INVALID_STATE
}
h := (*(*cgo.Handle)(db.private_data))
h := handleFromPtr(db.private_data)
db.private_data = nil

cdb := h.Value().(*cDatabase)
h.Delete()
if cdb.db != nil {
cdb.db.Close()
cdb.db = nil
}
cdb.opts = nil
if db.private_data != nil {
C.free(unsafe.Pointer(db.private_data))
db.private_data = nil
}
h.Delete()
// manually trigger GC for two reasons:
// 1. ASAN expects the release callback to be called before
// the process ends, but GC is not deterministic. So by manually
Expand Down Expand Up @@ -1029,15 +1025,14 @@ func {{.Prefix}}ConnectionRelease(cnxn *C.struct_AdbcConnection, err *C.struct_A
if !checkConnAlloc(cnxn, err, "AdbcConnectionRelease") {
return C.ADBC_STATUS_INVALID_STATE
}
h := (*(*cgo.Handle)(cnxn.private_data))
h := handleFromPtr(cnxn.private_data)
cnxn.private_data = nil

conn := h.Value().(*cConn)
h.Delete()
defer func() {
conn.cancelContext()
conn.cnxn = nil
C.free(cnxn.private_data)
cnxn.private_data = nil
h.Delete()
// manually trigger GC for two reasons:
// 1. ASAN expects the release callback to be called before
// the process ends, but GC is not deterministic. So by manually
Expand Down Expand Up @@ -1479,15 +1474,14 @@ func {{.Prefix}}StatementRelease(stmt *C.struct_AdbcStatement, err *C.struct_Adb
if !checkStmtAlloc(stmt, err, "AdbcStatementRelease") {
return C.ADBC_STATUS_INVALID_STATE
}
h := (*(*cgo.Handle)(stmt.private_data))
h := handleFromPtr(stmt.private_data)
stmt.private_data = nil

st := h.Value().(*cStmt)
h.Delete()
defer func() {
st.cancelContext()
st.stmt = nil
C.free(stmt.private_data)
stmt.private_data = nil
h.Delete()
// manually trigger GC for two reasons:
// 1. ASAN expects the release callback to be called before
// the process ends, but GC is not deterministic. So by manually
Expand Down
56 changes: 25 additions & 31 deletions go/adbc/pkg/flightsql/driver.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 25 additions & 31 deletions go/adbc/pkg/panicdummy/driver.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading