Fix pg_tle sizeof/INTERNALLENGTH mismatch, exact leaf recheck
The pg_tle struct has been 104 bytes since v0.1.0, but INTERNALLENGTH is 112. The size comment claimed "11 doubles (88 bytes)" — there are 10 (80 bytes). Every palloc(sizeof(pg_tle)) across the codebase allocated 104 bytes while PostgreSQL's datumCopy/heap_form_tuple copied 112, causing an 8-byte overread. Fix: add _reserved[8] to pg_tle, making sizeof(pg_tle) == 112. This is backward compatible — existing on-disk tuples already have 112 bytes allocated (from typlen), with zeros in the trailing 8. Also in gist_tle.c: - Remove TLE_TYPLEN band-aid, use sizeof(pg_tle) everywhere - Set recheck = false for leaf entries in consistent: the orbital key is computed identically to the SQL operator, so the GiST leaf check is exact (eliminates unnecessary heap fetches)
This commit is contained in:
parent
347acf0906
commit
de742fc3aa
@ -44,13 +44,7 @@ PG_FUNCTION_INFO_V1(gist_tle_distance);
|
|||||||
/* Floating-point comparison tolerance (km and radians) */
|
/* Floating-point comparison tolerance (km and radians) */
|
||||||
#define KEY_EPSILON 1.0e-9
|
#define KEY_EPSILON 1.0e-9
|
||||||
|
|
||||||
/*
|
/* sizeof(pg_tle) == 112, matching INTERNALLENGTH in CREATE TYPE. */
|
||||||
* The SQL type's INTERNALLENGTH. sizeof(pg_tle) is 104 due to struct
|
|
||||||
* packing, but the SQL definition declares 112. All allocations that
|
|
||||||
* become index datums must use TLE_TYPLEN so that PostgreSQL's
|
|
||||||
* index_form_tuple() never reads past the allocation.
|
|
||||||
*/
|
|
||||||
#define TLE_TYPLEN 112
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 2-D orbital key extracted from a TLE's mean elements.
|
* 2-D orbital key extracted from a TLE's mean elements.
|
||||||
@ -240,10 +234,9 @@ tle_alt_distance(PG_FUNCTION_ARGS)
|
|||||||
* Leaf entries carry the full pg_tle; we compress to tle_orbital_key.
|
* Leaf entries carry the full pg_tle; we compress to tle_orbital_key.
|
||||||
* Internal entries are already tle_orbital_key from union operations.
|
* Internal entries are already tle_orbital_key from union operations.
|
||||||
*
|
*
|
||||||
* The allocation must be TLE_TYPLEN bytes (matching INTERNALLENGTH),
|
* The allocation must be sizeof(pg_tle) bytes — which matches
|
||||||
* not sizeof(tle_orbital_key) or sizeof(pg_tle). GiST's
|
* INTERNALLENGTH — not sizeof(tle_orbital_key). GiST's
|
||||||
* index_form_tuple() copies typlen bytes from the datum pointer;
|
* index_form_tuple() copies typlen bytes from the datum pointer.
|
||||||
* under-allocating causes a heap buffer overread.
|
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
gist_tle_compress(PG_FUNCTION_ARGS)
|
gist_tle_compress(PG_FUNCTION_ARGS)
|
||||||
@ -254,7 +247,7 @@ gist_tle_compress(PG_FUNCTION_ARGS)
|
|||||||
if (entry->leafkey)
|
if (entry->leafkey)
|
||||||
{
|
{
|
||||||
pg_tle *tle = (pg_tle *) DatumGetPointer(entry->key);
|
pg_tle *tle = (pg_tle *) DatumGetPointer(entry->key);
|
||||||
tle_orbital_key *key = (tle_orbital_key *) palloc0(TLE_TYPLEN);
|
tle_orbital_key *key = (tle_orbital_key *) palloc0(sizeof(pg_tle));
|
||||||
|
|
||||||
tle_to_orbital_key(tle, key);
|
tle_to_orbital_key(tle, key);
|
||||||
|
|
||||||
@ -286,8 +279,10 @@ gist_tle_decompress(PG_FUNCTION_ARGS)
|
|||||||
* gist_tle_consistent -- can this subtree contain matches for the query?
|
* gist_tle_consistent -- can this subtree contain matches for the query?
|
||||||
*
|
*
|
||||||
* Checks overlap in both altitude AND inclination dimensions.
|
* Checks overlap in both altitude AND inclination dimensions.
|
||||||
* Always sets recheck = true because 2-D overlap is only a necessary
|
*
|
||||||
* condition -- the real conjunction test requires propagation.
|
* For leaf entries, recheck = false: the orbital key is computed
|
||||||
|
* identically to the SQL operator, so the GiST check is exact.
|
||||||
|
* For internal nodes, recheck is irrelevant (GiST ignores it).
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
gist_tle_consistent(PG_FUNCTION_ARGS)
|
gist_tle_consistent(PG_FUNCTION_ARGS)
|
||||||
@ -303,7 +298,12 @@ gist_tle_consistent(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
tle_to_orbital_key(query, &query_key);
|
tle_to_orbital_key(query, &query_key);
|
||||||
|
|
||||||
*recheck = true;
|
/*
|
||||||
|
* Leaf keys are exact (same tle_to_orbital_key as the operator),
|
||||||
|
* so no recheck needed. For internal nodes PostgreSQL ignores
|
||||||
|
* the flag, but we set true by convention.
|
||||||
|
*/
|
||||||
|
*recheck = !GIST_LEAF(entry);
|
||||||
|
|
||||||
switch (strategy)
|
switch (strategy)
|
||||||
{
|
{
|
||||||
@ -353,7 +353,7 @@ gist_tle_union(PG_FUNCTION_ARGS)
|
|||||||
tle_orbital_key *result;
|
tle_orbital_key *result;
|
||||||
tle_orbital_key *cur;
|
tle_orbital_key *cur;
|
||||||
|
|
||||||
result = (tle_orbital_key *) palloc0(TLE_TYPLEN);
|
result = (tle_orbital_key *) palloc0(sizeof(pg_tle));
|
||||||
cur = (tle_orbital_key *) DatumGetPointer(entryvec->vector[0].key);
|
cur = (tle_orbital_key *) DatumGetPointer(entryvec->vector[0].key);
|
||||||
*result = *cur;
|
*result = *cur;
|
||||||
|
|
||||||
@ -363,7 +363,7 @@ gist_tle_union(PG_FUNCTION_ARGS)
|
|||||||
key_merge(result, cur);
|
key_merge(result, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
*sizep = TLE_TYPLEN;
|
*sizep = sizeof(pg_tle);
|
||||||
|
|
||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
@ -508,8 +508,8 @@ gist_tle_picksplit(PG_FUNCTION_ARGS)
|
|||||||
splitvec->spl_nright = 0;
|
splitvec->spl_nright = 0;
|
||||||
|
|
||||||
/* Compute union keys and assign entries */
|
/* Compute union keys and assign entries */
|
||||||
left_union = (tle_orbital_key *) palloc0(TLE_TYPLEN);
|
left_union = (tle_orbital_key *) palloc0(sizeof(pg_tle));
|
||||||
right_union = (tle_orbital_key *) palloc0(TLE_TYPLEN);
|
right_union = (tle_orbital_key *) palloc0(sizeof(pg_tle));
|
||||||
|
|
||||||
/* Seed the unions from the first entry in each half */
|
/* Seed the unions from the first entry in each half */
|
||||||
cur = (tle_orbital_key *) DatumGetPointer(
|
cur = (tle_orbital_key *) DatumGetPointer(
|
||||||
|
|||||||
@ -75,10 +75,13 @@ typedef struct pg_tle
|
|||||||
char classification; /* U = unclassified */
|
char classification; /* U = unclassified */
|
||||||
char ephemeris_type; /* 0 = SGP4/SDP4 default */
|
char ephemeris_type; /* 0 = SGP4/SDP4 default */
|
||||||
char intl_desig[9]; /* international designator, null-terminated */
|
char intl_desig[9]; /* international designator, null-terminated */
|
||||||
char _pad; /* alignment */
|
char _pad; /* alignment to int32 boundary */
|
||||||
|
char _reserved[8]; /* match INTERNALLENGTH = 112 */
|
||||||
} pg_tle;
|
} pg_tle;
|
||||||
|
|
||||||
/* Size: 11 doubles (88 bytes) + 3 int32 (12 bytes) + 12 chars = 112 bytes */
|
/* Size: 10 doubles (80) + 3 int32 (12) + 12 chars + 8 reserved = 112 bytes
|
||||||
|
* Must match INTERNALLENGTH in CREATE TYPE. PostgreSQL's datumCopy() and
|
||||||
|
* heap_form_tuple() copy exactly typlen bytes from any pg_tle pointer. */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user