Skip to content

Commit b2f6754

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 534cce2 commit b2f6754

File tree

1 file changed

+44
-30
lines changed

1 file changed

+44
-30
lines changed

contrib/uuid-ossp/uuid-ossp.c

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,42 @@ pguuid_complain(uuid_rc_t rc)
7979
errmsg("OSSP uuid library failure: error code %d", rc)));
8080
}
8181

82+
/*
83+
* We create a uuid_t object just once per session and re-use it for all
84+
* operations in this module. OSSP UUID caches the system MAC address and
85+
* other state in this object. Reusing the object has a number of benefits:
86+
* saving the cycles needed to fetch the system MAC address over and over,
87+
* reducing the amount of entropy we draw from /dev/urandom, and providing a
88+
* positive guarantee that successive generated V1-style UUIDs don't collide.
89+
* (On a machine fast enough to generate multiple UUIDs per microsecond,
90+
* or whatever the system's wall-clock resolution is, we'd otherwise risk
91+
* collisions whenever random initialization of the uuid_t's clock sequence
92+
* value chanced to produce duplicates.)
93+
*
94+
* However: when we're doing V3 or V5 UUID creation, uuid_make needs two
95+
* uuid_t objects, one holding the namespace UUID and one for the result.
96+
* It's unspecified whether it's safe to use the same uuid_t for both cases,
97+
* so let's cache a second uuid_t for use as the namespace holder object.
98+
*/
99+
static uuid_t *
100+
get_cached_uuid_t(int which)
101+
{
102+
static uuid_t *cached_uuid[2] = {NULL, NULL};
103+
104+
if (cached_uuid[which] == NULL)
105+
{
106+
uuid_rc_t rc;
107+
108+
rc = uuid_create(&cached_uuid[which]);
109+
if (rc != UUID_RC_OK)
110+
{
111+
cached_uuid[which] = NULL;
112+
pguuid_complain(rc);
113+
}
114+
}
115+
return cached_uuid[which];
116+
}
117+
82118
static char *
83119
uuid_to_string(const uuid_t *uuid)
84120
{
@@ -109,20 +145,14 @@ string_to_uuid(const char *str, uuid_t *uuid)
109145
static Datum
110146
special_uuid_value(const char *name)
111147
{
112-
uuid_t *uuid;
148+
uuid_t *uuid = get_cached_uuid_t(0);
113149
char *str;
114150
uuid_rc_t rc;
115151

116-
rc = uuid_create(&uuid);
117-
if (rc != UUID_RC_OK)
118-
pguuid_complain(rc);
119152
rc = uuid_load(uuid, name);
120153
if (rc != UUID_RC_OK)
121154
pguuid_complain(rc);
122155
str = uuid_to_string(uuid);
123-
rc = uuid_destroy(uuid);
124-
if (rc != UUID_RC_OK)
125-
pguuid_complain(rc);
126156

127157
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
128158
}
@@ -166,20 +196,14 @@ uuid_ns_x500(PG_FUNCTION_ARGS)
166196
static Datum
167197
uuid_generate_internal(int mode, const uuid_t *ns, const char *name)
168198
{
169-
uuid_t *uuid;
199+
uuid_t *uuid = get_cached_uuid_t(0);
170200
char *str;
171201
uuid_rc_t rc;
172202

173-
rc = uuid_create(&uuid);
174-
if (rc != UUID_RC_OK)
175-
pguuid_complain(rc);
176203
rc = uuid_make(uuid, mode, ns, name);
177204
if (rc != UUID_RC_OK)
178205
pguuid_complain(rc);
179206
str = uuid_to_string(uuid);
180-
rc = uuid_destroy(uuid);
181-
if (rc != UUID_RC_OK)
182-
pguuid_complain(rc);
183207

184208
return DirectFunctionCall1(uuid_in, CStringGetDatum(str));
185209
}
@@ -202,25 +226,15 @@ uuid_generate_v1mc(PG_FUNCTION_ARGS)
202226
static Datum
203227
uuid_generate_v35_internal(int mode, pg_uuid_t *ns, text *name)
204228
{
205-
uuid_t *ns_uuid;
206-
Datum result;
207-
uuid_rc_t rc;
229+
uuid_t *ns_uuid = get_cached_uuid_t(1);
208230

209-
rc = uuid_create(&ns_uuid);
210-
if (rc != UUID_RC_OK)
211-
pguuid_complain(rc);
212-
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out, UUIDPGetDatum(ns))),
231+
string_to_uuid(DatumGetCString(DirectFunctionCall1(uuid_out,
232+
UUIDPGetDatum(ns))),
213233
ns_uuid);
214234

215-
result = uuid_generate_internal(mode,
216-
ns_uuid,
217-
text_to_cstring(name));
218-
219-
rc = uuid_destroy(ns_uuid);
220-
if (rc != UUID_RC_OK)
221-
pguuid_complain(rc);
222-
223-
return result;
235+
return uuid_generate_internal(mode,
236+
ns_uuid,
237+
text_to_cstring(name));
224238
}
225239

226240

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