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

Commita916cb9

Browse files
committed
Avoid overflow hazard when clamping group counts to "long int".
Several places in the planner tried to clamp a double value to fitin a "long" by doing(long) Min(x, (double) LONG_MAX);This is subtly incorrect, because it casts LONG_MAX to double andpotentially back again. If long is 64 bits then the double valueis inexact, and the platform might round it up to LONG_MAX+1resulting in an overflow and an undesirably negative output.While it's not hard to rewrite the expression into a safe form,let's put it into a common function to reduce the risk of someonedoing it wrong in future.In principle this is a bug fix, but since the problem could onlymanifest with group count estimates exceeding 2^63, it seems unlikelythat anyone has actually hit this or will do so anytime soon. We'refixing it mainly to satisfy fuzzer-type tools. That being the case,a HEAD-only fix seems sufficient.Andrey LepikhovDiscussion:https://postgr.es/m/ebbc2efb-7ef9-bf2f-1ada-d6ec48f70e58@postgrespro.ru
1 parentac1ae47 commita916cb9

File tree

4 files changed

+33
-6
lines changed

4 files changed

+33
-6
lines changed

‎src/backend/executor/nodeSubplan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
*/
2727
#include"postgres.h"
2828

29-
#include<limits.h>
3029
#include<math.h>
3130

3231
#include"access/htup_details.h"
@@ -35,6 +34,7 @@
3534
#include"miscadmin.h"
3635
#include"nodes/makefuncs.h"
3736
#include"nodes/nodeFuncs.h"
37+
#include"optimizer/optimizer.h"
3838
#include"utils/array.h"
3939
#include"utils/lsyscache.h"
4040
#include"utils/memutils.h"
@@ -498,7 +498,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
498498
node->havehashrows= false;
499499
node->havenullrows= false;
500500

501-
nbuckets=(long)Min(planstate->plan->plan_rows, (double)LONG_MAX);
501+
nbuckets=clamp_cardinality_to_long(planstate->plan->plan_rows);
502502
if (nbuckets<1)
503503
nbuckets=1;
504504

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171

7272
#include"postgres.h"
7373

74+
#include<limits.h>
7475
#include<math.h>
7576

7677
#include"access/amapi.h"
@@ -215,6 +216,32 @@ clamp_row_est(double nrows)
215216
returnnrows;
216217
}
217218

219+
/*
220+
* clamp_cardinality_to_long
221+
*Cast a Cardinality value to a sane long value.
222+
*/
223+
long
224+
clamp_cardinality_to_long(Cardinalityx)
225+
{
226+
/*
227+
* Just for paranoia's sake, ensure we do something sane with negative or
228+
* NaN values.
229+
*/
230+
if (isnan(x))
231+
returnLONG_MAX;
232+
if (x <=0)
233+
return0;
234+
235+
/*
236+
* If "long" is 64 bits, then LONG_MAX cannot be represented exactly as a
237+
* double. Casting it to double and back may well result in overflow due
238+
* to rounding, so avoid doing that. We trust that any double value that
239+
* compares strictly less than "(double) LONG_MAX" will cast to a
240+
* representable "long" value.
241+
*/
242+
return (x< (double)LONG_MAX) ? (long)x :LONG_MAX;
243+
}
244+
218245

219246
/*
220247
* cost_seqscan

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
*/
1717
#include"postgres.h"
1818

19-
#include<limits.h>
2019
#include<math.h>
2120

2221
#include"access/sysattr.h"
@@ -2724,7 +2723,7 @@ create_setop_plan(PlannerInfo *root, SetOpPath *best_path, int flags)
27242723
flags |CP_LABEL_TLIST);
27252724

27262725
/* Convert numGroups to long int --- but 'ware overflow! */
2727-
numGroups=(long)Min(best_path->numGroups, (double)LONG_MAX);
2726+
numGroups=clamp_cardinality_to_long(best_path->numGroups);
27282727

27292728
plan=make_setop(best_path->cmd,
27302729
best_path->strategy,
@@ -2761,7 +2760,7 @@ create_recursiveunion_plan(PlannerInfo *root, RecursiveUnionPath *best_path)
27612760
tlist=build_path_tlist(root,&best_path->path);
27622761

27632762
/* Convert numGroups to long int --- but 'ware overflow! */
2764-
numGroups=(long)Min(best_path->numGroups, (double)LONG_MAX);
2763+
numGroups=clamp_cardinality_to_long(best_path->numGroups);
27652764

27662765
plan=make_recursive_union(tlist,
27672766
leftplan,
@@ -6554,7 +6553,7 @@ make_agg(List *tlist, List *qual,
65546553
longnumGroups;
65556554

65566555
/* Reduce to long, but 'ware overflow! */
6557-
numGroups=(long)Min(dNumGroups, (double)LONG_MAX);
6556+
numGroups=clamp_cardinality_to_long(dNumGroups);
65586557

65596558
node->aggstrategy=aggstrategy;
65606559
node->aggsplit=aggsplit;

‎src/include/optimizer/optimizer.h

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

9797
externdoubleclamp_row_est(doublenrows);
98+
externlongclamp_cardinality_to_long(Cardinalityx);
9899

99100
/* in path/indxpath.c: */
100101

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp