Skip to content

Free the C string MEOS hands back, in the wrappers that convert one - #22

Merged
estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:fix/free-returned-c-strings
Sep 3, 2026
Merged

Free the C string MEOS hands back, in the wrappers that convert one#22
estebanzimanyi merged 1 commit into
MobilityDB:mainfrom
estebanzimanyi:fix/free-returned-c-strings

Conversation

@estebanzimanyi

Copy link
Copy Markdown
Member

WITNESS: 125 generated wrappers end return C.GoString(_cret), nil and none of
them frees _cret. The generator is not free-blind -- it emits C.free 295
times, every one for an INPUT it allocated itself (_c_endian, _c_name,
_c_path). It frees what it allocates and drops what MEOS hands back.

The return belongs to the caller, and MEOS's own example says so:
meos/examples/03_berlinmod_assemble.c reads
char *trip_str = temporal_as_hexwkb(trip, WKB_EXTENDED, &length); and then
free(trip_str). C.GoString copies into Go memory, so the C allocation is
unreachable the moment such a wrapper returns.

MEASURED, 200000 calls of TemporalAsHexwkb against resident memory: the
generated wrapper grows +19444 KB where this package's hand-written accessor,
which frees, grows +4488 KB. With the free emitted the same wrapper grows
+424 KB.

THE DISCRIMINATOR IS THE C DECLARATION, so nothing is inferred from a name or a
group: char * belongs to the caller, const char * belongs to MEOS and must
never be freed. tools/codegen.py carries separate rows for the two
types whose conversions otherwise coincide; the free hangs off that distinction
and is deferred, so it runs after the copy, and it sits after the errno guard so a
failed call never reaches it.

The regenerated surface splits exactly along that line: of the 125 wrappers,
115 free and 10 do not, and those 10 are precisely the const char * entries --
geo_typename, interptype_name, meos_pc_schema_compression,
meos_pc_schema_xml, meosoper_name, meostype_name,
temporal_basetype_name, temporal_interp, temporal_subtype,
tempsubtype_name. Freeing one of those would be a fault, so the zero there
matters as much as the 115.

The suite reads 121 result lines, 0 skipped, and go build ./functions is
clean.

WITNESS: 125 generated wrappers end `return C.GoString(_cret), nil` and none of
them frees `_cret`. The generator is not free-blind -- it emits `C.free` 295
times, every one for an INPUT it allocated itself (`_c_endian`, `_c_name`,
`_c_path`). It frees what it allocates and drops what MEOS hands back.

The return belongs to the caller, and MEOS's own example says so:
`meos/examples/03_berlinmod_assemble.c` reads
`char *trip_str = temporal_as_hexwkb(trip, WKB_EXTENDED, &length);` and then
`free(trip_str)`. `C.GoString` copies into Go memory, so the C allocation is
unreachable the moment such a wrapper returns.

MEASURED, 200000 calls of `TemporalAsHexwkb` against resident memory: the
generated wrapper grows +19444 KB where this package's hand-written accessor,
which frees, grows +4488 KB. With the free emitted the same wrapper grows
+424 KB.

THE DISCRIMINATOR IS THE C DECLARATION, so nothing is inferred from a name or a
group: `char *` belongs to the caller, `const char *` belongs to MEOS and must
never be freed. `tools/codegen.py` carries separate rows for the two
types whose conversions otherwise coincide; the free hangs off that distinction
and is deferred, so it runs after the copy, and it sits after the errno guard so a
failed call never reaches it.

The regenerated surface splits exactly along that line: of the 125 wrappers,
115 free and 10 do not, and those 10 are precisely the `const char *` entries --
`geo_typename`, `interptype_name`, `meos_pc_schema_compression`,
`meos_pc_schema_xml`, `meosoper_name`, `meostype_name`,
`temporal_basetype_name`, `temporal_interp`, `temporal_subtype`,
`tempsubtype_name`. Freeing one of those would be a fault, so the zero there
matters as much as the 115.

The suite reads 121 result lines, 0 skipped, and `go build ./functions` is
clean.
@estebanzimanyi
estebanzimanyi merged commit ab2cf23 into MobilityDB:main Sep 3, 2026
2 checks passed
@estebanzimanyi
estebanzimanyi deleted the fix/free-returned-c-strings branch September 3, 2026 11:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant