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

Commit7e1ce2b

Browse files
committed
Prevent integer overflow when forming tuple width estimates.
It's at least theoretically possible to overflow int32 when adding upcolumn width estimates to make a row width estimate. (The bug exampleisn't terribly convincing as a real use-case, but perhaps wide joinswould provide a more plausible route to trouble.) This'd lead toassertion failures or silly planner behavior. To forestall it, makethe relevant functions compute their running sums in int64 arithmeticand then clamp to int32 range at the end. We can reasonably assumethat MaxAllocSize is a hard limit on actual tuple width, so clampingto that is simply a correction for dubious input values, and there'sno need to go as far as widening width variables to int64 everywhere.Per bug #18247 from RekGRpth. There've been no reports of this issuearising in practical cases, so I feel no need to back-patch.Richard Guo and Tom LaneDiscussion:https://postgr.es/m/18247-11ac477f02954422@postgresql.org
1 parent2a607fb commit7e1ce2b

File tree

6 files changed

+52
-15
lines changed

6 files changed

+52
-15
lines changed

‎src/backend/optimizer/path/costsize.c

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,35 @@ clamp_row_est(double nrows)
218218
returnnrows;
219219
}
220220

221+
/*
222+
* clamp_width_est
223+
*Force a tuple-width estimate to a sane value.
224+
*
225+
* The planner represents datatype width and tuple width estimates as int32.
226+
* When summing column width estimates to create a tuple width estimate,
227+
* it's possible to reach integer overflow in edge cases. To ensure sane
228+
* behavior, we form such sums in int64 arithmetic and then apply this routine
229+
* to clamp to int32 range.
230+
*/
231+
int32
232+
clamp_width_est(int64tuple_width)
233+
{
234+
/*
235+
* Anything more than MaxAllocSize is clearly bogus, since we could not
236+
* create a tuple that large.
237+
*/
238+
if (tuple_width>MaxAllocSize)
239+
return (int32)MaxAllocSize;
240+
241+
/*
242+
* Unlike clamp_row_est, we just Assert that the value isn't negative,
243+
* rather than masking such errors.
244+
*/
245+
Assert(tuple_width >=0);
246+
247+
return (int32)tuple_width;
248+
}
249+
221250
/*
222251
* clamp_cardinality_to_long
223252
*Cast a Cardinality value to a sane long value.
@@ -6101,7 +6130,7 @@ static void
61016130
set_rel_width(PlannerInfo*root,RelOptInfo*rel)
61026131
{
61036132
Oidreloid=planner_rt_fetch(rel->relid,root)->relid;
6104-
int32tuple_width=0;
6133+
int64tuple_width=0;
61056134
boolhave_wholerow_var= false;
61066135
ListCell*lc;
61076136

@@ -6213,7 +6242,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
62136242
*/
62146243
if (have_wholerow_var)
62156244
{
6216-
int32wholerow_width=MAXALIGN(SizeofHeapTupleHeader);
6245+
int64wholerow_width=MAXALIGN(SizeofHeapTupleHeader);
62176246

62186247
if (reloid!=InvalidOid)
62196248
{
@@ -6230,7 +6259,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
62306259
wholerow_width+=rel->attr_widths[i-rel->min_attr];
62316260
}
62326261

6233-
rel->attr_widths[0-rel->min_attr]=wholerow_width;
6262+
rel->attr_widths[0-rel->min_attr]=clamp_width_est(wholerow_width);
62346263

62356264
/*
62366265
* Include the whole-row Var as part of the output tuple. Yes, that
@@ -6239,8 +6268,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
62396268
tuple_width+=wholerow_width;
62406269
}
62416270

6242-
Assert(tuple_width >=0);
6243-
rel->reltarget->width=tuple_width;
6271+
rel->reltarget->width=clamp_width_est(tuple_width);
62446272
}
62456273

62466274
/*
@@ -6258,7 +6286,7 @@ set_rel_width(PlannerInfo *root, RelOptInfo *rel)
62586286
PathTarget*
62596287
set_pathtarget_cost_width(PlannerInfo*root,PathTarget*target)
62606288
{
6261-
int32tuple_width=0;
6289+
int64tuple_width=0;
62626290
ListCell*lc;
62636291

62646292
/* Vars are assumed to have cost zero, but other exprs do not */
@@ -6282,8 +6310,7 @@ set_pathtarget_cost_width(PlannerInfo *root, PathTarget *target)
62826310
}
62836311
}
62846312

6285-
Assert(tuple_width >=0);
6286-
target->width=tuple_width;
6313+
target->width=clamp_width_est(tuple_width);
62876314

62886315
returntarget;
62896316
}

‎src/backend/optimizer/plan/planner.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4610,6 +4610,7 @@ create_one_window_path(PlannerInfo *root,
46104610
* Note: a WindowFunc adds nothing to the target's eval costs; but
46114611
* we do need to account for the increase in tlist width.
46124612
*/
4613+
int64tuple_width=window_target->width;
46134614
ListCell*lc2;
46144615

46154616
window_target=copy_pathtarget(window_target);
@@ -4618,8 +4619,9 @@ create_one_window_path(PlannerInfo *root,
46184619
WindowFunc*wfunc=lfirst_node(WindowFunc,lc2);
46194620

46204621
add_column_to_pathtarget(window_target, (Expr*)wfunc,0);
4621-
window_target->width+=get_typavgwidth(wfunc->wintype,-1);
4622+
tuple_width+=get_typavgwidth(wfunc->wintype,-1);
46224623
}
4624+
window_target->width=clamp_width_est(tuple_width);
46234625
}
46244626
else
46254627
{

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
375375
SpecialJoinInfo*sjinfo)
376376
{
377377
Relidsrelids=joinrel->relids;
378+
int64tuple_width=joinrel->reltarget->width;
378379
ListCell*lc;
379380

380381
foreach(lc,root->placeholder_list)
@@ -419,7 +420,7 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
419420
cost_qual_eval_node(&cost, (Node*)phv->phexpr,root);
420421
joinrel->reltarget->cost.startup+=cost.startup;
421422
joinrel->reltarget->cost.per_tuple+=cost.per_tuple;
422-
joinrel->reltarget->width+=phinfo->ph_width;
423+
tuple_width+=phinfo->ph_width;
423424
}
424425
}
425426

@@ -443,6 +444,8 @@ add_placeholders_to_joinrel(PlannerInfo *root, RelOptInfo *joinrel,
443444
phinfo->ph_lateral);
444445
}
445446
}
447+
448+
joinrel->reltarget->width=clamp_width_est(tuple_width);
446449
}
447450

448451
/*

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
11371137
int32
11381138
get_rel_data_width(Relationrel,int32*attr_widths)
11391139
{
1140-
int32tuple_width=0;
1140+
int64tuple_width=0;
11411141
inti;
11421142

11431143
for (i=1;i <=RelationGetNumberOfAttributes(rel);i++)
@@ -1167,7 +1167,7 @@ get_rel_data_width(Relation rel, int32 *attr_widths)
11671167
tuple_width+=item_width;
11681168
}
11691169

1170-
returntuple_width;
1170+
returnclamp_width_est(tuple_width);
11711171
}
11721172

11731173
/*

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include"optimizer/clauses.h"
2323
#include"optimizer/cost.h"
2424
#include"optimizer/inherit.h"
25+
#include"optimizer/optimizer.h"
2526
#include"optimizer/pathnode.h"
2627
#include"optimizer/paths.h"
2728
#include"optimizer/placeholder.h"
@@ -1092,6 +1093,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
10921093
boolcan_null)
10931094
{
10941095
Relidsrelids=joinrel->relids;
1096+
int64tuple_width=joinrel->reltarget->width;
10951097
ListCell*vars;
10961098
ListCell*lc;
10971099

@@ -1144,7 +1146,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
11441146
joinrel->reltarget->exprs=lappend(joinrel->reltarget->exprs,
11451147
phv);
11461148
/* Bubbling up the precomputed result has cost zero */
1147-
joinrel->reltarget->width+=phinfo->ph_width;
1149+
tuple_width+=phinfo->ph_width;
11481150
}
11491151
continue;
11501152
}
@@ -1165,7 +1167,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
11651167
list_nth(root->row_identity_vars,var->varattno-1);
11661168

11671169
/* Update reltarget width estimate from RowIdentityVarInfo */
1168-
joinrel->reltarget->width+=ridinfo->rowidwidth;
1170+
tuple_width+=ridinfo->rowidwidth;
11691171
}
11701172
else
11711173
{
@@ -1181,7 +1183,7 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
11811183
continue;/* nope, skip it */
11821184

11831185
/* Update reltarget width estimate from baserel's attr_widths */
1184-
joinrel->reltarget->width+=baserel->attr_widths[ndx];
1186+
tuple_width+=baserel->attr_widths[ndx];
11851187
}
11861188

11871189
/*
@@ -1221,6 +1223,8 @@ build_joinrel_tlist(PlannerInfo *root, RelOptInfo *joinrel,
12211223

12221224
/* Vars have cost zero, so no need to adjust reltarget->cost */
12231225
}
1226+
1227+
joinrel->reltarget->width=clamp_width_est(tuple_width);
12241228
}
12251229

12261230
/*

‎src/include/optimizer/optimizer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ extern PGDLLIMPORT double recursive_worktable_factor;
9090
externPGDLLIMPORTinteffective_cache_size;
9191

9292
externdoubleclamp_row_est(doublenrows);
93+
externint32clamp_width_est(int64tuple_width);
9394
externlongclamp_cardinality_to_long(Cardinalityx);
9495

9596
/* in path/indxpath.c: */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp