8000 Fix datumSerialize infrastructure to not crash on non-varlena data. · codeimmortal/postgres@9bf4068 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit 9bf4068

Browse files
committed
Fix datumSerialize infrastructure to not crash on non-varlena data.
Commit 1efc7e5 did a poor job of emulating existing logic for touching Datums that might be expanded-object pointers. It didn't check for typlen being -1 first, which meant it could crash on fixed-length pass-by-ref values, and probably on cstring values as well. It also didn't use DatumGetPointer before VARATT_IS_EXTERNAL_EXPANDED, which while currently harmless is not according to documentation nor prevailing style. I also think the lack of any explanation as to why datumSerialize makes these particular nonobvious choices is pretty awful, so fix that. Per report from Jarred Ward. Back-patch to 9.6 where this code came in. Discussion: https://postgr.es/m/6F61E6D2-2F5E-4794-9479-A429BE1CEA4B@simple.com
1 parent 77d2c00 commit 9bf4068

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

src/backend/utils/adt/datum.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,11 @@ datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
268268
/* no need to use add_size, can't overflow */
269269
if (typByVal)
270270
sz += sizeof(Datum);
271-
else if (VARATT_IS_EXTERNAL_EXPANDED(value))
271+
else if (typLen == -1 &&
272+
VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
272273
{
273-
ExpandedObjectHeader *eoh = DatumGetEOHP(value);
274-
275-
sz += EOH_get_flat_size(eoh);
274+
/* Expanded objects need to be flattened, see comment below */
275+
sz += EOH_get_flat_size(DatumGetEOHP(value));
276276
}
277277
else
278278
sz += datumGetSize(value, typByVal, typLen);
@@ -286,6 +286,13 @@ datumEstimateSpace(Datum value, bool isnull, bool typByVal, int typLen)
286286
*
287287
* Serialize a possibly-NULL datum into caller-provided storage.
288288
*
289+
* Note: "expanded" objects are flattened so as to produce a self-contained
290+
* representation, but other sorts of toast pointers are transferred as-is.
291+
* This is because the intended use of this function is to pass the value
292+
* to another process within the same database server. The other process
293+
* could not access an "expanded" object within this process's memory, but
294+
* we assume it can dereference the same TOAST pointers this one can.
295+
*
289296
* The format is as follows: first, we write a 4-byte header word, which
290297
* is either the length of a pass-by-reference datum, -1 for a
291298
* pass-by-value datum, or -2 for a NULL. If the value is NULL, nothing
@@ -310,7 +317,8 @@ datumSerialize(Datum value, bool isnull, bool typByVal, int typLen,
310317
header = -2;
311318
else if (typByVal)
312319
header = -1;
313-
else if (VARATT_IS_EXTERNAL_EXPANDED(value))
320+
else if (typLen == -1 &&
321+
VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(value)))
314322
{
315323
eoh = DatumGetEOHP(value);
316324
header = EOH_get_flat_size(eoh);

0 commit comments

Comments
 (0)
0