Description
The valToBuffer() function in helpers.go creates a C.CString allocation that is never freed, causing a significant memory leak. This is a hot path function called for every string column in every row returned by queries.
Current Code
func valToBuffer(val interface{}, oid C.Oid, buffer C.StringInfo) (err error) {
// ...
C.fdw_appendBinaryStringInfo(buffer, C.CString(valueString), C.int(len(valueString)))
return
}
Problem
C.CString() allocates memory on the C heap which must be explicitly freed with C.free(). The current code passes the result directly to fdw_appendBinaryStringInfo without storing it, making it impossible to free.
Impact
- Severity: High - This is a hot path
- Frequency: Called for every string column in every row
- Memory leaked: Length of each string value + overhead
- Example: Query returning 10,000 rows × 10 string columns = 100,000 leaks per query
Proposed Fix
Store CString result and free immediately after use:
cValueString := C.CString(valueString)
C.fdw_appendBinaryStringInfo(buffer, cValueString, C.int(len(valueString)))
C.free(unsafe.Pointer(cValueString))
Important: Use explicit C.free() instead of defer because:
- This is a hot path called thousands/millions of times per query
defer adds ~50-100ns overhead per call plus heap allocation
- The immediate free pattern is already used elsewhere in the codebase (see
errors.go)
Description
The
valToBuffer()function inhelpers.gocreates aC.CStringallocation that is never freed, causing a significant memory leak. This is a hot path function called for every string column in every row returned by queries.Current Code
Problem
C.CString()allocates memory on the C heap which must be explicitly freed withC.free(). The current code passes the result directly tofdw_appendBinaryStringInfowithout storing it, making it impossible to free.Impact
Proposed Fix
Store CString result and free immediately after use:
Important: Use explicit
C.free()instead ofdeferbecause:deferadds ~50-100ns overhead per call plus heap allocationerrors.go)