Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Data-UUID CPAN distribution.

Report information
The Basics
Id: 737
Status: resolved
Priority: 0/
Queue: Data-UUID

People
Owner: Nobody in particular
Requestors: rpb [...] hybyte.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: (no value)
Fixed in: (no value)



Subject: Incorrect time based UUID
Data::UUID version 0.06 Perl 5.6.0 for i586-linux RedHat Linux 2.4.7-10 The timestamp encoded in the time based UUID is always within 214 seconds of 1970-01-01 00:00:00. The code following the gettimeofday call is not casting one of the intermediate values correctly. I'm not sure if the code I have replaced it with (see attachment) is efficient, but it appears to work. This bug appears in the documentation - 4162f712-1dd2-11b2-b17e converts to a time very close to 1970-01-01 00:00:00. Thanks for the module!
#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include "UUID.h" static uuid_t NameSpace_DNS = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ 0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } }; static uuid_t NameSpace_URL = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */ 0x6ba7b811, 0x9dad, 0x11d1, 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } }; static uuid_t NameSpace_OID = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */ 0x6ba7b812, 0x9dad, 0x11d1, 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } }; uuid_t NameSpace_X500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */ 0x6ba7b814, 0x9dad, 0x11d1, 0x80, 0xb4, { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 } }; static void format_uuid_v1( uuid_t *uuid, unsigned16 clock_seq, uuid_time_t timestamp, uuid_node_t node ) { uuid->time_low = (unsigned long)(timestamp & 0xFFFFFFFF); uuid->time_mid = (unsigned short)((timestamp >> 32) & 0xFFFF); uuid->time_hi_and_version = (unsigned short)((timestamp >> 48) & 0x0FFF); uuid->time_hi_and_version |= (1 << 12); uuid->clock_seq_low = clock_seq & 0xFF; uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8; uuid->clock_seq_hi_and_reserved |= 0x80; memcpy(&uuid->node, &node, sizeof uuid->node); } static void get_current_time(uuid_time_t * timestamp) { uuid_time_t time_now; static uuid_time_t time_last; static unsigned16 uuids_this_tick; static int inited = 0; if (!inited) { get_system_time(&time_now); uuids_this_tick = UUIDS_PER_TICK; inited = 1; }; while (1) { get_system_time(&time_now); if (time_last != time_now) { uuids_this_tick = 0; break; }; if (uuids_this_tick < UUIDS_PER_TICK) { uuids_this_tick++; break; }; }; *timestamp = time_now + uuids_this_tick; } static unsigned16 true_random(void) { static int inited = 0; uuid_time_t time_now; if (!inited) { get_system_time(&time_now); time_now = time_now/UUIDS_PER_TICK; srand((unsigned int)(((time_now >> 32) ^ time_now)&0xffffffff)); inited = 1; }; return (rand()); } static void format_uuid_v3( uuid_t *uuid, unsigned char hash[16] ) { memcpy(uuid, hash, sizeof(uuid_t)); uuid->time_low = ntohl(uuid->time_low); uuid->time_mid = ntohs(uuid->time_mid); uuid->time_hi_and_version = ntohs(uuid->time_hi_and_version); uuid->time_hi_and_version &= 0x0FFF; uuid->time_hi_and_version |= (3 << 12); uuid->clock_seq_hi_and_reserved &= 0x3F; uuid->clock_seq_hi_and_reserved |= 0x80; } static void get_system_time(uuid_time_t *uuid_time) { #if defined __CYGWIN__ ULARGE_INTEGER time; GetSystemTimeAsFileTime((FILETIME *)&time); time.QuadPart += (unsigned __int64) (1000*1000*10) * (unsigned __int64) (60 * 60 * 24) * (unsigned __int64) (17+30+31+365*18+5); *uuid_time = time.QuadPart; #else struct timeval tp; gettimeofday(&tp, (struct timezone *)0); *uuid_time = tp.tv_sec; *uuid_time *= 10000000; *uuid_time += tp.tv_usec * 10; *uuid_time += I64(0x01B21DD213814000); #endif } static void get_random_info(unsigned char seed[16]) { MD5_CTX c; #if defined __CYGWIN__ typedef struct { MEMORYSTATUS m; SYSTEM_INFO s; FILETIME t; LARGE_INTEGER pc; DWORD tc; DWORD l; char hostname[MAX_COMPUTERNAME_LENGTH + 1]; } randomness; #else typedef struct { long hostid; struct timeval t; char hostname[257]; } randomness; #endif randomness r; MD5Init(&c); #if defined __CYGWIN__ GlobalMemoryStatus(&r.m); GetSystemInfo(&r.s); GetSystemTimeAsFileTime(&r.t); QueryPerformanceCounter(&r.pc); r.tc = GetTickCount(); r.l = MAX_COMPUTERNAME_LENGTH + 1; GetComputerName(r.hostname, &r.l ); #else r.hostid = gethostid(); gettimeofday(&r.t, (struct timezone *)0); gethostname(r.hostname, 256); #endif MD5Update(&c, (unsigned char*)&r, sizeof(randomness)); MD5Final(seed, &c); } SV* make_ret(const uuid_t u, int type) { char buf[BUFSIZ]; unsigned char *from, *to; STRLEN len; int i; memset(buf, 0x00, BUFSIZ); switch(type) { case F_BIN: memcpy(buf, (void*)&u, sizeof(uuid_t)); len = sizeof(uuid_t); break; case F_STR: sprintf(buf, "%8.8X-%4.4X-%4.4X-%2.2X%2.2X-", (unsigned int)u.time_low, u.time_mid, u.time_hi_and_version, u.clock_seq_hi_and_reserved, u.clock_seq_low); for(i = 0; i < 6; i++ ) sprintf(buf+strlen(buf), "%2.2X", u.node[i]); len = strlen(buf); break; case F_HEX: sprintf(buf, "0x%8.8X%4.4X%4.4X%2.2X%2.2X", (unsigned int)u.time_low, u.time_mid, u.time_hi_and_version, u.clock_seq_hi_and_reserved, u.clock_seq_low); for(i = 0; i < 6; i++ ) sprintf(buf+strlen(buf), "%2.2X", u.node[i]); len = strlen(buf); break; case F_B64: for(from = (unsigned char*)&u, to = (unsigned char*)buf, i = sizeof(u); i > 0; i -= 3, from += 3) { *to++ = base64[from[0]>>2]; switch(i) { case 1: *to++ = base64[(from[0]&0x03)<<4]; *to++ = '='; *to++ = '='; break; case 2: *to++ = base64[((from[0]&0x03)<<4) | ((from[1]&0xF0)>>4)]; *to++ = base64[(from[1]&0x0F)<<2]; *to++ = '='; break; default: *to++ = base64[((from[0]&0x03)<<4) | ((from[1]&0xF0)>>4)]; *to++ = base64[((from[1]&0x0F)<<2) | ((from[2]&0xC0)>>6)]; *to++ = base64[(from[2]&0x3F)]; } } len = strlen(buf); break; default: croak("invalid type: %d\n", type); break; } return sv_2mortal(newSVpv(buf,len)); } MODULE = Data::UUID PACKAGE = Data::UUID PROTOTYPES: DISABLE void constant(sv,arg) PREINIT: STRLEN len; char *pv; INPUT: SV *sv char *s = SvPV(sv, len); PPCODE: pv = 0; len = sizeof(uuid_t); if (strEQ(s,"NameSpace_DNS")) pv = (char*)&NameSpace_DNS; if (strEQ(s,"NameSpace_URL")) pv = (char*)&NameSpace_URL; if (strEQ(s,"NameSpace_X500")) pv = (char*)&NameSpace_X500; if (strEQ(s,"NameSpace_OID")) pv = (char*)&NameSpace_OID; ST(0) = sv_2mortal(newSVpv(pv, len)); XSRETURN(1); uuid_context_t* new(class) char *class; PREINIT: FILE *fd; unsigned char seed[16]; uuid_time_t timestamp; mode_t mask; CODE: Newz(0,RETVAL,1,uuid_context_t); if ((fd = fopen(UUID_STATE_NV_STORE, "rb"))) { fread(&(RETVAL->state), sizeof(uuid_state_t), 1, fd); fclose(fd); get_current_time(&timestamp); RETVAL->next_save = timestamp; } if ((fd = fopen(UUID_NODEID_NV_STORE, "rb"))) { fread(&(RETVAL->nodeid), sizeof(uuid_node_t), 1, fd ); fclose(fd); } else { get_random_info(seed); seed[0] |= 0x80; memcpy(&(RETVAL->nodeid), seed, sizeof(uuid_node_t)); mask = umask(0); if ((fd = fopen(UUID_NODEID_NV_STORE, "wb"))) { fwrite(&(RETVAL->nodeid), sizeof(uuid_node_t), 1, fd); fclose(fd); }; umask(mask); } errno = 0; OUTPUT: RETVAL void create(self) uuid_context_t *self; ALIAS: Data::UUID::create_bin = F_BIN Data::UUID::create_str = F_STR Data::UUID::create_hex = F_HEX Data::UUID::create_b64 = F_B64 PREINIT: uuid_time_t timestamp; unsigned16 clockseq; uuid_t uuid; FILE *fd; mode_t mask; PPCODE: clockseq = self->state.cs; get_current_time(&timestamp); if ( self->state.ts == I64(0) || memcmp(&(self->nodeid), &(self->state.node), sizeof(uuid_node_t))) clockseq = true_random(); else if (timestamp < self->state.ts) clockseq++; format_uuid_v1(&uuid, clockseq, timestamp, self->nodeid); self->state.node = self->nodeid; self->state.ts = timestamp; self->state.cs = clockseq; if (timestamp > self->next_save ) { mask = umask(0); if((fd = fopen(UUID_STATE_NV_STORE, "wb"))) { LOCK(fd); fwrite(&(self->state), sizeof(uuid_state_t), 1, fd); UNLOCK(fd); fclose(fd); } umask(mask); self->next_save = timestamp + (10 * 10 * 1000 * 1000); } ST(0) = make_ret(uuid, ix); XSRETURN(1); void create_from_name(self,nsid,name) uuid_context_t *self; uuid_t *nsid; char *name; ALIAS: Data::UUID::create_from_name_bin = F_BIN Data::UUID::create_from_name_str = F_STR Data::UUID::create_from_name_hex = F_HEX Data::UUID::create_from_name_b64 = F_B64 PREINIT: MD5_CTX c; unsigned char hash[16]; uuid_t net_nsid; uuid_t uuid; PPCODE: net_nsid = *nsid; net_nsid.time_low = htonl(net_nsid.time_low); net_nsid.time_mid = htons(net_nsid.time_mid); net_nsid.time_hi_and_version = htons(net_nsid.time_hi_and_version); MD5Init(&c); MD5Update(&c, (unsigned char*)&net_nsid, sizeof(uuid_t)); MD5Update(&c, (unsigned char*)name, strlen(name)); MD5Final(hash, &c); format_uuid_v3(&uuid, hash); ST(0) = make_ret(uuid, ix); XSRETURN(1); int compare(self,u1,u2) uuid_context_t *self; uuid_t *u1; uuid_t *u2; PREINIT: int i; CODE: RETVAL = 0; CHECK(u1->time_low, u2->time_low); CHECK(u1->time_mid, u2->time_mid); CHECK(u1->time_hi_and_version, u2->time_hi_and_version); CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved); CHECK(u1->clock_seq_low, u2->clock_seq_low); for (i = 0; i < 6; i++) { if (u1->node[i] < u2->node[i]) RETVAL = -1; if (u1->node[i] > u2->node[i]) RETVAL = 1; } OUTPUT: RETVAL void to_string(self,uuid) uuid_context_t *self; uuid_t *uuid; ALIAS: Data::UUID::to_hexstring = F_HEX Data::UUID::to_b64string = F_B64 PPCODE: ST(0) = make_ret(*uuid, ix ? ix : F_STR); XSRETURN(1); void from_string(self,str) uuid_context_t *self; char *str; ALIAS: Data::UUID::from_hexstring = F_HEX Data::UUID::from_b64string = F_B64 PREINIT: uuid_t uuid; char *from, *to; int i, c; unsigned char buf[4]; PPCODE: switch(ix) { case F_BIN: case F_STR: case F_HEX: from = str; memset(&uuid, 0x00, sizeof(uuid_t)); if ( from[0] == '0' && from[1] == 'x' ) from += 2; for (i = 0; i < sizeof(uuid_t); i++) { if (*from == '-') from++; if (sscanf(from, "%2x", &c) != 1) croak("from_string(%s) failed...\n", str); ((unsigned char*)&uuid)[i] = (unsigned char)c; from += 2; } uuid.time_low = ntohl(uuid.time_low); uuid.time_mid = ntohs(uuid.time_mid); uuid.time_hi_and_version = ntohs(uuid.time_hi_and_version); break; case F_B64: from = str; to = (char*)&uuid; while(from < (str + strlen(str))) { i = 0; memset(buf, 254, 4); do { c = index64[(int)*from++]; if (c != 255) buf[i++] = (unsigned char)c; if (from == (str + strlen(str))) break; } while (i < 4); if (buf[0] == 254 || buf[1] == 254) break; *to++ = (buf[0] << 2) | ((buf[1] & 0x30) >> 4); if (buf[2] == 254) break; *to++ = ((buf[1] & 0x0F) << 4) | ((buf[2] & 0x3C) >> 2); if (buf[3] == 254) break; *to++ = ((buf[2] & 0x03) << 6) | buf[3]; } break; default: croak("invalid type %d\n", ix); break; } ST(0) = make_ret(uuid, F_BIN); XSRETURN(1); void DESTROY(self) uuid_context_t *self; PREINIT: FILE *fd; CODE: if ((fd = fopen(UUID_STATE_NV_STORE, "wb"))) { LOCK(fd); fwrite(&(self->state), sizeof(uuid_state_t), 1, fd); UNLOCK(fd); fclose(fd); }; Safefree(self);
Subject: Re: [cpan #737] Incorrect time based UUID
To: bug-Data-UUID [...] rt.cpan.org
From: golomshtok_alexander [...] jpmorgan.com
Date: Wed, 12 Jun 2002 14:45:11 -0400
thank you....will make sure i include your fix in the new release (in a coupla weeks)... regards, alex g bug-Data-UUID@rt.cpan.org on 06/12/2002 02:03:20 PM Please respond to bug-Data-UUID@rt.cpan.org To: "'AdminCc of cpan Ticket #737'": ;:;@ cc: Subject: [cpan #737] Incorrect time based UUID This message about Data-UUID was sent to you by guest via rt.cpan.org Full context and any attached attachments can be found at: <URL: https://rt.cpan.org/Ticket/Display.html?id=737 > Data::UUID version 0.06 Perl 5.6.0 for i586-linux RedHat Linux 2.4.7-10 The timestamp encoded in the time based UUID is always within 214 seconds of 1970-01-01 00:00:00. The code following the gettimeofday call is not casting one of the intermediate values correctly. I'm not sure if the code I have replaced it with (see attachment) is efficient, but it appears to work. This bug appears in the documentation - 4162f712-1dd2-11b2-b17e converts to a time very close to 1970-01-01 00:00:00. Thanks for the module! This communication is for informational purposes only. It is not intended as an offer or solicitation for the purchase or sale of any financial instrument or as an official confirmation of any transaction. All market prices, data and other information are not warranted as to completeness or accuracy and are subject to change without notice. Any comments or statements made herein do not necessarily reflect those of J.P. Morgan Chase & Co., its subsidiaries and affiliates.
From: "Rodger Bagnall" <rpb [...] hybyte.com>
To: <bug-Data-UUID [...] rt.cpan.org>
Subject: Re: [cpan #737] AutoReply: Incorrect time based UUID
Date: Fri, 14 Jun 2002 16:58:25 +0100
Version 0.07 fixes this bug. Please close 737.