Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d08c44f

Browse files
committed
Fix mvdistinct and dependencies size calculations
The formulas used to calculate size while (de)serializing mvndistinct and functional dependencies were based on offset() of the structs. But that is incorrect, because the structures are not copied directly, we we copy the individual fields directly. At the moment this works fine, because there is no alignment padding on any platform we support. But it might break if we ever added some fields into any of the structs, for example. It's also confusing. Fixed by reworking the macros to directly sum sizes of serialized fields. The macros are now useful only for serialiation, so there is no point in keeping them in the public header file. So make them private by moving them to the .c files. Also adds a couple more asserts to check the serialization, and fixes an incorrect allocation of MVDependency instead of (MVDependency *). Reported-By: Tom Lane Discussion: https://postgr.es/m/29785.1555365602@sss.pgh.pa.us
1 parent bfbc150 commit d08c44f

File tree

3 files changed

+56
-40
lines changed

3 files changed

+56
-40
lines changed

src/backend/statistics/dependencies.c

+29-11
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@
3232
#include "utils/syscache.h"
3333
#include "utils/typcache.h"
3434

35+
/* size of the struct header fields (magic, type, ndeps) */
36+
#define SizeOfHeader (3 * sizeof(uint32))
37+
38+
/* size of a serialized dependency (degree, natts, atts) */
39+
#define SizeOfItem(natts) \
40+
(sizeof(double) + sizeof(AttrNumber) * (1 + (natts)))
41+
42+
/* minimal size of a dependency (with two attributes) */
43+
#define MinSizeOfItem SizeOfItem(2)
44+
45+
/* minimal size of dependencies, when all deps are minimal */
46+
#define MinSizeOfItems(ndeps) \
47+
(SizeOfHeader + (ndeps) * MinSizeOfItem)
48+
3549
/*
3650
* Internal state for DependencyGenerator of dependencies. Dependencies are similar to
3751
* k-permutations of n elements, except that the order does not matter for the
@@ -408,7 +422,7 @@ statext_dependencies_build(int numrows, HeapTuple *rows, Bitmapset *attrs,
408422
dependencies->ndeps++;
409423
dependencies = (MVDependencies *) repalloc(dependencies,
410424
offsetof(MVDependencies, deps)
411-
+ dependencies->ndeps * sizeof(MVDependency));
425+
+ dependencies->ndeps * sizeof(MVDependency *));
412426

413427
dependencies->deps[dependencies->ndeps - 1] = d;
414428
}
@@ -436,12 +450,11 @@ statext_dependencies_serialize(MVDependencies *dependencies)
436450
Size len;
437451

438452
/* we need to store ndeps, with a number of attributes for each one */
439-
len = VARHDRSZ + SizeOfDependencies
440-
+ dependencies->ndeps * SizeOfDependency;
453+
len = VARHDRSZ + SizeOfHeader;
441454

442455
/* and also include space for the actual attribute numbers and degrees */
443456
for (i = 0; i < dependencies->ndeps; i++)
444-
len += (sizeof(AttrNumber) * dependencies->deps[i]->nattributes);
457+
len += SizeOfItem(dependencies->deps[i]->nattributes);
445458

446459
output = (bytea *) palloc0(len);
447460
SET_VARSIZE(output, len);
@@ -461,15 +474,22 @@ statext_dependencies_serialize(MVDependencies *dependencies)
461474
{
462475
MVDependency *d = dependencies->deps[i];
463476

464-
memcpy(tmp, d, SizeOfDependency);
465-
tmp += SizeOfDependency;
477+
memcpy(tmp, &d->degree, sizeof(double));
478+
tmp += sizeof(double);
479+
480+
memcpy(tmp, &d->nattributes, sizeof(AttrNumber));
481+
tmp += sizeof(AttrNumber);
466482

467483
memcpy(tmp, d->attributes, sizeof(AttrNumber) * d->nattributes);
468484
tmp += sizeof(AttrNumber) * d->nattributes;
469485

486+
/* protect against overflow */
470487
Assert(tmp <= ((char *) output + len));
471488
}
472489

490+
/* make sure we've produced exactly the right amount of data */
491+
Assert(tmp == ((char *) output + len));
492+
473493
return output;
474494
}
475495

@@ -487,9 +507,9 @@ statext_dependencies_deserialize(bytea *data)
487507
if (data == NULL)
488508
return NULL;
489509

490-
if (VARSIZE_ANY_EXHDR(data) < SizeOfDependencies)
510+
if (VARSIZE_ANY_EXHDR(data) < SizeOfHeader)
491511
elog(ERROR, "invalid MVDependencies size %zd (expected at least %zd)",
492-
VARSIZE_ANY_EXHDR(data), SizeOfDependencies);
512+
VARSIZE_ANY_EXHDR(data), SizeOfHeader);
493513

494514
/* read the MVDependencies header */
495515
dependencies = (MVDependencies *) palloc0(sizeof(MVDependencies));
@@ -519,9 +539,7 @@ statext_dependencies_deserialize(bytea *data)
519539
errmsg("invalid zero-length item array in MVDependencies")));
520540

521541
/* what minimum bytea size do we expect for those parameters */
522-
min_expected_size = SizeOfDependencies +
523-
dependencies->ndeps * (SizeOfDependency +
524-
sizeof(AttrNumber) * 2);
542+
min_expected_size = SizeOfItem(dependencies->ndeps);
525543

526544
if (VARSIZE_ANY_EXHDR(data) < min_expected_size)
527545
elog(ERROR, "invalid dependencies size %zd (expected at least %zd)",

src/backend/statistics/mvdistinct.c

+26-11
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ static double estimate_ndistinct(double totalrows, int numrows, int d, int f1);
4343
static int n_choose_k(int n, int k);
4444
static int num_combinations(int n);
4545

46+
/* size of the struct header fields (magic, type, nitems) */
47+
#define SizeOfHeader (3 * sizeof(uint32))
48+
49+
/* size of a serialized ndistinct item (coefficient, natts, atts) */
50+
#define SizeOfItem(natts) \
51+
(sizeof(double) + sizeof(int) + (natts) * sizeof(AttrNumber))
52+
53+
/* minimal size of a ndistinct item (with two attributes) */
54+
#define MinSizeOfItem SizeOfItem(2)
55+
56+
/* minimal size of mvndistinct, when all items are minimal */
57+
#define MinSizeOfItems(nitems) \
58+
(SizeOfHeader + (nitems) * MinSizeOfItem)
59+
4660
/* Combination generator API */
4761

4862
/* internal state for generator of k-combinations of n elements */
@@ -168,8 +182,7 @@ statext_ndistinct_serialize(MVNDistinct *ndistinct)
168182
* Base size is size of scalar fields in the struct, plus one base struct
169183
* for each item, including number of items for each.
170184
*/
171-
len = VARHDRSZ + SizeOfMVNDistinct +
172-
ndistinct->nitems * (offsetof(MVNDistinctItem, attrs) + sizeof(int));
185+
len = VARHDRSZ + SizeOfHeader;
173186

174187
/* and also include space for the actual attribute numbers */
175188
for (i = 0; i < ndistinct->nitems; i++)
@@ -178,7 +191,8 @@ statext_ndistinct_serialize(MVNDistinct *ndistinct)
178191

179192
nmembers = bms_num_members(ndistinct->items[i].attrs);
180193
Assert(nmembers >= 2);
181-
len += sizeof(AttrNumber) * nmembers;
194+
195+
len += SizeOfItem(nmembers);
182196
}
183197

184198
output = (bytea *) palloc(len);
@@ -195,8 +209,7 @@ statext_ndistinct_serialize(MVNDistinct *ndistinct)
195209
tmp += sizeof(uint32);
196210

197211
/*
198-
* store number of attributes and attribute numbers for each ndistinct
199-
* entry
212+
* store number of attributes and attribute numbers for each entry
200213
*/
201214
for (i = 0; i < ndistinct->nitems; i++)
202215
{
@@ -218,9 +231,13 @@ statext_ndistinct_serialize(MVNDistinct *ndistinct)
218231
tmp += sizeof(AttrNumber);
219232
}
220233

234+
/* protect against overflows */
221235
Assert(tmp <= ((char *) output + len));
222236
}
223237

238+
/* check we used exactly the expected space */
239+
Assert(tmp == ((char *) output + len));
240+
224241
return output;
225242
}
226243

@@ -241,9 +258,9 @@ statext_ndistinct_deserialize(bytea *data)
241258
return NULL;
242259

243260
/* we expect at least the basic fields of MVNDistinct struct */
244-
if (VARSIZE_ANY_EXHDR(data) < SizeOfMVNDistinct)
261+
if (VARSIZE_ANY_EXHDR(data) < SizeOfHeader)
245262
elog(ERROR, "invalid MVNDistinct size %zd (expected at least %zd)",
246-
VARSIZE_ANY_EXHDR(data), SizeOfMVNDistinct);
263+
VARSIZE_ANY_EXHDR(data), SizeOfHeader);
247264

248265
/* initialize pointer to the data part (skip the varlena header) */
249266
tmp = VARDATA_ANY(data);
@@ -272,9 +289,7 @@ statext_ndistinct_deserialize(bytea *data)
272289
errmsg("invalid zero-length item array in MVNDistinct")));
273290

274291
/* what minimum bytea size do we expect for those parameters */
275-
minimum_size = (SizeOfMVNDistinct +
276-
ndist.nitems * (SizeOfMVNDistinctItem +
277-
sizeof(AttrNumber) * 2));
292+
minimum_size = MinSizeOfItems(ndist.nitems);
278293
if (VARSIZE_ANY_EXHDR(data) < minimum_size)
279294
ereport(ERROR,
280295
(errcode(ERRCODE_DATA_CORRUPTED),
@@ -285,7 +300,7 @@ statext_ndistinct_deserialize(bytea *data)
285300
* Allocate space for the ndistinct items (no space for each item's
286301
* attnos: those live in bitmapsets allocated separately)
287302
*/
288-
ndistinct = palloc0(MAXALIGN(SizeOfMVNDistinct) +
303+
ndistinct = palloc0(MAXALIGN(offsetof(MVNDistinct, items)) +
289304
(ndist.nitems * sizeof(MVNDistinctItem)));
290305
ndistinct->magic = ndist.magic;
291306
ndistinct->type = ndist.type;

src/include/statistics/statistics.h

+1-18
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,6 @@ typedef struct MVNDistinctItem
2929
Bitmapset *attrs; /* attr numbers of items */
3030
} MVNDistinctItem;
3131

32-
/* size of the struct, excluding attribute list */
33-
#define SizeOfMVNDistinctItem \
34-
(offsetof(MVNDistinctItem, ndistinct) + sizeof(double))
35-
3632
/* A MVNDistinct object, comprising all possible combinations of columns */
3733
typedef struct MVNDistinct
3834
{
@@ -42,13 +38,7 @@ typedef struct MVNDistinct
4238
MVNDistinctItem items[FLEXIBLE_ARRAY_MEMBER];
4339
} MVNDistinct;
4440

45-
/* size of the struct excluding the items array */
46-
#define SizeOfMVNDistinct (offsetof(MVNDistinct, nitems) + sizeof(uint32))
47-
48-
49-
/* size of the struct excluding the items array */
50-
#define SizeOfMVNDistinct (offsetof(MVNDistinct, nitems) + sizeof(uint32))
51-
41+
/* Multivariate functional dependencies */
5242
#define STATS_DEPS_MAGIC 0xB4549A2C /* marks serialized bytea */
5343
#define STATS_DEPS_TYPE_BASIC 1 /* basic dependencies type */
5444

@@ -63,10 +53,6 @@ typedef struct MVDependency
6353
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]; /* attribute numbers */
6454
} MVDependency;
6555

66-
/* size of the struct excluding the deps array */
67-
#define SizeOfDependency \
68-
(offsetof(MVDependency, nattributes) + sizeof(AttrNumber))
69-
7056
typedef struct MVDependencies
7157
{
7258
uint32 magic; /* magic constant marker */
@@ -75,9 +61,6 @@ typedef struct MVDependencies
7561
MVDependency *deps[FLEXIBLE_ARRAY_MEMBER]; /* dependencies */
7662
} MVDependencies;
7763

78-
/* size of the struct excluding the deps array */
79-
#define SizeOfDependencies (offsetof(MVDependencies, ndeps) + sizeof(uint32))
80-
8164
/* used to flag stats serialized to bytea */
8265
#define STATS_MCV_MAGIC 0xE1A651C2 /* marks serialized bytea */
8366
#define STATS_MCV_TYPE_BASIC 1 /* basic MCV list type */

0 commit comments

Comments
 (0)