Skip to content

Commit 25d2380

Browse files
anse1df7cb
authored andcommitted
Fix crash when unit_reset() runs into an OOM error.
Make code to regenerate the lookup tables robust against out-of-memory errors by keeping the old tables around until the new ones are ready. The previous code left pointers to destroyed tables around on OOM, leading to a server crash. Reported by sqlsmith.
1 parent feffd11 commit 25d2380

File tree

1 file changed

+56
-26
lines changed

1 file changed

+56
-26
lines changed

unit.c

+56-26
Original file line numberDiff line numberDiff line change
@@ -48,55 +48,87 @@ unit_get_definitions(void)
4848
int i;
4949
unit_names_t *unit_name;
5050
unit_dimensions_t *unit_dim;
51+
static HTAB *tmp_unit_names;
52+
static HTAB *tmp_unit_dimensions;
5153

52-
/* unit_names: char *name -> Unit unit
54+
/* tmp_unit_names: char *name -> Unit unit
5355
* Lookup table that initially contains the base units and will cache all
5456
* units resolved at run time
5557
*/
5658
hinfo.keysize = UNIT_NAME_LENGTH;
5759
hinfo.entrysize = sizeof(unit_names_t);
5860
Assert(UNIT_NAME_LENGTH + sizeof(UnitShift) == sizeof(unit_names_t));
59-
unit_names = hash_create("unit_names",
61+
tmp_unit_names = hash_create("unit_names",
6062
20,
6163
&hinfo,
6264
HASH_ELEM); /* Set keysize and entrysize */
6365

64-
for (i = 0; derived_units[i].name; i++)
66+
PG_TRY();
6567
{
66-
if (derived_units[i].flags & U_DERIVED)
67-
break; // FIXME: split tables
68-
unit_name = hash_search(unit_names,
69-
derived_units[i].name,
70-
HASH_ENTER,
71-
NULL);
72-
strlcpy(unit_name->name, derived_units[i].name, UNIT_NAME_LENGTH);
73-
unit_name->unit_shift.unit.value = derived_units[i].factor;
74-
memcpy(unit_name->unit_shift.unit.units, derived_units[i].units, N_UNITS);
75-
unit_name->unit_shift.shift = 0.0;
68+
for (i = 0; derived_units[i].name; i++)
69+
{
70+
if (derived_units[i].flags & U_DERIVED)
71+
break; // FIXME: split tables
72+
unit_name = hash_search(tmp_unit_names,
73+
derived_units[i].name,
74+
HASH_ENTER,
75+
NULL);
76+
strlcpy(unit_name->name, derived_units[i].name, UNIT_NAME_LENGTH);
77+
unit_name->unit_shift.unit.value = derived_units[i].factor;
78+
memcpy(unit_name->unit_shift.unit.units, derived_units[i].units, N_UNITS);
79+
unit_name->unit_shift.shift = 0.0;
80+
}
81+
}
82+
PG_CATCH();
83+
{
84+
/* free partially initialized table */
85+
hash_destroy(tmp_unit_names);
86+
PG_RE_THROW();
7687
}
88+
PG_END_TRY();
89+
90+
/* No OOM errors were thrown, use the new table */
91+
if (unit_names)
92+
hash_destroy(unit_names);
93+
unit_names = tmp_unit_names;
7794

78-
/* unit_dimensions: char dimension[N_UNITS] -> char *name
95+
/* tmp_unit_dimensions: char dimension[N_UNITS] -> char *name
7996
* Lookup table for formatting the well-known derived units on output
8097
*/
8198
hinfo.keysize = N_UNITS;
8299
hinfo.entrysize = sizeof(unit_dimensions_t);
83100
Assert(N_UNITS + UNIT_NAME_LENGTH == sizeof(unit_dimensions_t));
84-
unit_dimensions = hash_create("unit_dimensions",
101+
tmp_unit_dimensions = hash_create("unit_dimensions",
85102
20,
86103
&hinfo,
87104
HASH_ELEM | HASH_BLOBS);
88105

89-
for (i = 0; derived_units[i].name; i++)
106+
PG_TRY();
90107
{
91-
if (! derived_units[i].flags & U_DERIVED)
92-
continue;
93-
unit_dim = hash_search(unit_dimensions,
94-
derived_units[i].units,
95-
HASH_ENTER,
96-
NULL);
97-
memcpy(unit_dim->units, derived_units[i].units, N_UNITS);
98-
strlcpy(unit_dim->name, derived_units[i].name, UNIT_NAME_LENGTH);
108+
for (i = 0; derived_units[i].name; i++)
109+
{
110+
if (! derived_units[i].flags & U_DERIVED)
111+
continue;
112+
unit_dim = hash_search(tmp_unit_dimensions,
113+
derived_units[i].units,
114+
HASH_ENTER,
115+
NULL);
116+
memcpy(unit_dim->units, derived_units[i].units, N_UNITS);
117+
strlcpy(unit_dim->name, derived_units[i].name, UNIT_NAME_LENGTH);
118+
}
119+
}
120+
PG_CATCH();
121+
{
122+
/* free partially initialized table */
123+
hash_destroy(tmp_unit_dimensions);
124+
PG_RE_THROW();
99125
}
126+
PG_END_TRY();
127+
128+
/* No OOM errors were thrown, use the new table */
129+
if (unit_dimensions)
130+
hash_destroy(unit_dimensions);
131+
unit_dimensions = tmp_unit_dimensions;
100132
}
101133

102134
/* module initialization */
@@ -946,8 +978,6 @@ Datum
946978
unit_reset(PG_FUNCTION_ARGS)
947979
{
948980
/* reinitialize hash tables */
949-
hash_destroy(unit_names);
950-
hash_destroy(unit_dimensions);
951981
unit_get_definitions();
952982

953983
PG_RETURN_VOID();

0 commit comments

Comments
 (0)