Skip to content

Commit c941aed

Browse files
committed
When using the OSSP UUID library, cache its uuid_t state object.
The original coding in contrib/uuid-ossp created and destroyed a uuid_t object (or, in some cases, even two of them) each time it was called. This is not the intended usage: you're supposed to keep the uuid_t object around so that the library can cache its state across uses. (Other UUID libraries seem to keep equivalent state behind-the-scenes in static variables, but OSSP chose differently.) Aside from being quite inefficient, creating a new uuid_t loses knowledge of the previously generated UUID, which in theory could result in duplicate V1-style UUIDs being created on sufficiently fast machines. On at least some platforms, creating a new uuid_t also draws some entropy from /dev/urandom, leaving less for the rest of the system. This seems sufficiently unpleasant to justify back-patching this change.
1 parent 25dd07e commit c941aed

File tree

1 file changed

+45
-31
lines changed

1 file changed

+45
-31
lines changed

contrib/uuid-ossp/uuid-ossp.c

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,42 @@ pguuid_complain(uuid_rc_t rc)
141141
errmsg("OSSP uuid library failure: error code %d", rc)));
142142
}
143143

144+
/*
145+
* We create a uuid_t object just once per session and re-use it for all
146+
* operations in this module. OSSP UUID caches the system MAC address and
147+
* other state in this object. Reusing the object has a number of benefits:
148+
* saving the cycles needed to fetch the system MAC address over and over,
149+
* reducing the amount of entropy we draw from /dev/urandom, and providing a
150+
* positive guarantee that successive generated V1-style UUIDs don't collide.
151+
* (On a machine fast enough to generate multiple UUIDs per microsecond,
152+
* or whatever the system's wall-clock resolution is, we'd otherwise risk
153+
* collisions whenever random initialization of the uuid_t's clock sequence
154+
* value chanced to produce duplicates.)
155+
*
156+
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
157+
* uuid_t objects, one holding the namespace UUID and one for the result.
158+
* It's unspecified whether it's safe to use the same uuid_t for both cases,
159+
* so let's cache a second uuid_t for use as the namespace holder object.
160+
*/
161+
static uuid_t *
162+
get_cached_uuid_t(int which)
163+
{
164+
static uuid_t *cached_uuid[2] = {NULL, NULL};
165+
166+
if (cached_uuid[which] == NULL)
167+
{
168+
uuid_rc_t rc;
169+
170+
rc = uuid_create(&cached_uuid[which]);
171+
if (rc != UUID_RC_OK)
172+
{
173+
cached_uuid[which] = NULL;
174+
pguuid_complain(rc);
175+
}
176+
}
177+
return cached_uuid[which];
178+
}
179+
144180
static char *
145181
uuid_to_string(const uuid_t *uuid)
146182
{
@@ -171,20 +207,14 @@ string_to_uuid(const char *str, uuid_t *uuid)
171207
static Datum
172208
special_uuid_value(const char *name)
173209
{
174-
uuid_t *uuid;
210+
uuid_t *uuid = get_cached_uuid_t(0);
175211
char *str;
176212
uuid_rc_t rc;
177213

178-
rc = uuid_create(&uuid);
179-
if (rc != UUID_RC_OK)
180-
pguuid_complain(rc);
181214
rc = uuid_load(uuid, name);
182215
if (rc != UUID_RC_OK)
183216
pguuid_complain(rc);
184217
str = uuid_to_string(uuid);
185-
rc = uuid_destroy(uuid);
186-
if (rc != UUID_RC_OK)
187-
pguuid_complain(rc);
188218

189219
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
190220
}
@@ -193,20 +223,14 @@ special_uuid_value(const char *name)
193223
static Datum
194224
uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
195225
{
196-
uuid_t *uuid;
226+
uuid_t *uuid = get_cached_uuid_t(0);
197227
char *str;
198228
uuid_rc_t rc;
199229

200-
rc = uuid_create(&uuid);
201-
if (rc != UUID_RC_OK)
202-
pguuid_complain(rc);
203230
rc = uuid_make(uuid, mode, ns, name);
204231
if (rc != UUID_RC_OK)
205232
pguuid_complain(rc);
206233
str = uuid_to_string(uuid);
207-
rc = uuid_destroy(uuid);
208-
if (rc != UUID_RC_OK)
209-
pguuid_complain(rc);
210234

211235
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
212236
}
@@ -215,26 +239,16 @@ uuid_generate_internal(int mode, const uuid_t *ns, const char *name, int len)
215239
static Datum
216240
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
217241
{
218-
uuid_t *ns_uuid;
219-
Datum result;
220-
uuid_rc_t rc;
242+
uuid_t *ns_uuid = get_cached_uuid_t(1);
221243

222-
rc = uuid_create(&ns_uuid);
223-
if (rc != UUID_RC_OK)
224-
pguuid_complain(rc);
225-
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
244+
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
245+
UUIDPGetDatum(ns))),
226246
ns_uuid);
227247

228-
result = uuid_generate_internal(mode,
229-
ns_uuid,
230-
text_to_cstring(name),
231-
0);
232-
233-
rc = uuid_destroy(ns_uuid);
234-
if (rc != UUID_RC_OK)
235-
pguuid_complain(rc);
236-
237-
return result;
248+
return uuid_generate_internal(mode,
249+
ns_uuid,
250+
text_to_cstring(name),
251+
0);
238252
}
239253

240254
#else /* !HAVE_UUID_OSSP */

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy