Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite80c85e

Browse files
committed
Add defenses against putting expanded objects into Const nodes.
Putting a reference to an expanded-format value into a Const node would bea bad idea for a couple of reasons. It'd be possible for the supposedlyimmutable Const to change value, if something modified the referencedvariable ... in fact, if the Const's reference were R/W, any function thathas the Const as argument might itself change it at runtime. Also, becausedatumIsEqual() is pretty simplistic, the Const might fail to compare equalto other Consts that it should compare equal to, notably including copiesof itself. This could lead to unexpected planner behavior, such as "couldnot find pathkey item to sort" errors or inferior plans.I have not been able to find any way to get an expanded value into a Constwithin the existing core code; but Paul Ramsey was able to trigger theproblem by writing a datatype input function that returns an expandedvalue.The best fix seems to be to establish a rule that varlena values beingplaced into Const nodes should be passed through pg_detoast_datum().That will do nothing (and cost little) in normal cases, but it will flattenexpanded values and thereby avoid the above problems. Also, it willconvert short-header or compressed values into canonical format, which willavoid possible unexpected lack-of-equality issues for those cases too.And it provides a last-ditch defense against putting a toasted value intoa Const, which we already knew was dangerous, cf commit2b0c86b.(In the light of this discussion, I'm no longer sure that that commitprovided 100% protection against such cases, but this fix should do it.)The test added in commit65c3d05 to catch datatype input functionswith unstable results would fail for functions that returned expandedvalues; but it seems a bit uncharitable to deem a result unstable justbecause it's expressed in expanded form, so revise the coding so that wecheck for bitwise equality only after applying pg_detoast_datum(). That'sa sufficient condition anyway given the new rule about detoasting whenforming a Const.Back-patch to 9.5 where the expanded-object facility was added. It'spossible that this should go back further; but in the absence of clearevidence that there's any live bug in older branches, I'll refrain for now.
1 parent34bda20 commite80c85e

File tree

5 files changed

+55
-31
lines changed

5 files changed

+55
-31
lines changed

‎src/backend/nodes/makefuncs.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include"catalog/pg_class.h"
1919
#include"catalog/pg_type.h"
20+
#include"fmgr.h"
2021
#include"nodes/makefuncs.h"
2122
#include"nodes/nodeFuncs.h"
2223
#include"utils/lsyscache.h"
@@ -302,6 +303,14 @@ makeConst(Oid consttype,
302303
{
303304
Const*cnst=makeNode(Const);
304305

306+
/*
307+
* If it's a varlena value, force it to be in non-expanded (non-toasted)
308+
* format; this avoids any possible dependency on external values and
309+
* improves consistency of representation, which is important for equal().
310+
*/
311+
if (!constisnull&&constlen==-1)
312+
constvalue=PointerGetDatum(PG_DETOAST_DATUM(constvalue));
313+
305314
cnst->consttype=consttype;
306315
cnst->consttypmod=consttypmod;
307316
cnst->constcollid=constcollid;

‎src/backend/optimizer/util/clauses.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4655,7 +4655,8 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
46554655
*
46564656
* Also, if it's varlena, forcibly detoast it. This protects us against
46574657
* storing TOAST pointers into plans that might outlive the referenced
4658-
* data.
4658+
* data. (makeConst would handle detoasting anyway, but it's worth a few
4659+
* extra lines here so that we can do the copy and detoast in one step.)
46594660
*/
46604661
if (!const_is_null)
46614662
{

‎src/backend/parser/parse_coerce.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include"parser/parse_relation.h"
2727
#include"parser/parse_type.h"
2828
#include"utils/builtins.h"
29+
#include"utils/datum.h"
2930
#include"utils/lsyscache.h"
3031
#include"utils/syscache.h"
3132
#include"utils/typcache.h"
@@ -308,6 +309,43 @@ coerce_type(ParseState *pstate, Node *node,
308309
NULL,
309310
inputTypeMod);
310311

312+
/*
313+
* If it's a varlena value, force it to be in non-expanded
314+
* (non-toasted) format; this avoids any possible dependency on
315+
* external values and improves consistency of representation.
316+
*/
317+
if (!con->constisnull&&newcon->constlen==-1)
318+
newcon->constvalue=
319+
PointerGetDatum(PG_DETOAST_DATUM(newcon->constvalue));
320+
321+
#ifdefRANDOMIZE_ALLOCATED_MEMORY
322+
323+
/*
324+
* For pass-by-reference data types, repeat the conversion to see if
325+
* the input function leaves any uninitialized bytes in the result. We
326+
* can only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is
327+
* enabled, so we don't bother testing otherwise. The reason we don't
328+
* want any instability in the input function is that comparison of
329+
* Const nodes relies on bytewise comparison of the datums, so if the
330+
* input function leaves garbage then subexpressions that should be
331+
* identical may not get recognized as such. See pgsql-hackers
332+
* discussion of 2008-04-04.
333+
*/
334+
if (!con->constisnull&& !newcon->constbyval)
335+
{
336+
Datumval2;
337+
338+
val2=stringTypeDatum(baseType,
339+
DatumGetCString(con->constvalue),
340+
inputTypeMod);
341+
if (newcon->constlen==-1)
342+
val2=PointerGetDatum(PG_DETOAST_DATUM(val2));
343+
if (!datumIsEqual(newcon->constvalue,val2, false,newcon->constlen))
344+
elog(WARNING,"type %s has unstable input conversion for \"%s\"",
345+
typeTypeName(baseType),DatumGetCString(con->constvalue));
346+
}
347+
#endif
348+
311349
cancel_parser_errposition_callback(&pcbstate);
312350

313351
result= (Node*)newcon;

‎src/backend/parser/parse_type.c

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include"parser/parse_type.h"
2424
#include"utils/array.h"
2525
#include"utils/builtins.h"
26-
#include"utils/datum.h"
2726
#include"utils/lsyscache.h"
2827
#include"utils/syscache.h"
2928

@@ -639,36 +638,8 @@ stringTypeDatum(Type tp, char *string, int32 atttypmod)
639638
Form_pg_typetypform= (Form_pg_type)GETSTRUCT(tp);
640639
Oidtypinput=typform->typinput;
641640
Oidtypioparam=getTypeIOParam(tp);
642-
Datumresult;
643641

644-
result=OidInputFunctionCall(typinput,string,
645-
typioparam,atttypmod);
646-
647-
#ifdefRANDOMIZE_ALLOCATED_MEMORY
648-
649-
/*
650-
* For pass-by-reference data types, repeat the conversion to see if the
651-
* input function leaves any uninitialized bytes in the result. We can
652-
* only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is enabled, so
653-
* we don't bother testing otherwise. The reason we don't want any
654-
* instability in the input function is that comparison of Const nodes
655-
* relies on bytewise comparison of the datums, so if the input function
656-
* leaves garbage then subexpressions that should be identical may not get
657-
* recognized as such. See pgsql-hackers discussion of 2008-04-04.
658-
*/
659-
if (string&& !typform->typbyval)
660-
{
661-
Datumresult2;
662-
663-
result2=OidInputFunctionCall(typinput,string,
664-
typioparam,atttypmod);
665-
if (!datumIsEqual(result,result2,typform->typbyval,typform->typlen))
666-
elog(WARNING,"type %s has unstable input conversion for \"%s\"",
667-
NameStr(typform->typname),string);
668-
}
669-
#endif
670-
671-
returnresult;
642+
returnOidInputFunctionCall(typinput,string,typioparam,atttypmod);
672643
}
673644

674645
/* given a typeid, return the type's typrelid (associated relation, if any) */

‎src/include/nodes/primnodes.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ typedef struct Var
165165

166166
/*
167167
* Const
168+
*
169+
* Note: for varlena data types, we make a rule that a Const node's value
170+
* must be in non-extended form (4-byte header, no compression or external
171+
* references). This ensures that the Const node is self-contained and makes
172+
* it more likely that equal() will see logically identical values as equal.
168173
*/
169174
typedefstructConst
170175
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp