public inbox for util-linux@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
@ 2025-12-13 20:04 Kiran Rangoon
  2025-12-13 23:36 ` Thomas Weißschuh 
  2025-12-14  1:01 ` [PATCH v2] " Kiran Rangoon
  0 siblings, 2 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-13 20:04 UTC (permalink / raw)
  To: util-linux; +Cc: Kiran Rangoon

gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
now use signed arithmetic to prevent unsigned wraparound.

This fixes uuidparse displaying far-future dates for historical UUIDs.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index c7516152b..b7fcc892d 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,15 +60,22 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static uint64_t gregorian_to_unix(uint64_t ts)
+static int64_t gregorian_to_unix(uint64_t ts)
 {
-	return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+    uint64_t offset = ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+
+    if (ts < offset) {
+        errno = EOVERFLOW;
+        return -1;
+    }
+
+    return ts - offset;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 {
 	uint32_t high;
-	uint64_t clock_reg;
+	int64_t clock_reg;
 
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
@@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 {
-	uint64_t clock_reg;
+	int64_t clock_reg;
 
 	clock_reg = uuid->time_low;
 	clock_reg <<= 16;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-13 20:04 [PATCH] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Kiran Rangoon
@ 2025-12-13 23:36 ` Thomas Weißschuh 
  2025-12-14  1:01 ` [PATCH v2] " Kiran Rangoon
  1 sibling, 0 replies; 19+ messages in thread
From: Thomas Weißschuh  @ 2025-12-13 23:36 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

Hey Kiran,

thanks for your patch!


Dec 14, 2025 05:04:23 Kiran Rangoon <kiranrangoon0@gmail.com>:

> gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
> for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
> now use signed arithmetic to prevent unsigned wraparound.
>
> This fixes uuidparse displaying far-future dates for historical UUIDs.

Can you add an example for the issue here?

>
> Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
> ---
> libuuid/src/uuid_time.c | 15 +++++++++++----
> 1 file changed, 11 insertions(+), 4 deletions(-)

Could you also add some tests?

>
> diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
> index c7516152b..b7fcc892d 100644
> --- a/libuuid/src/uuid_time.c
> +++ b/libuuid/src/uuid_time.c
> @@ -60,15 +60,22 @@
> /* prototype to make compiler happy */
> time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
>
> -static uint64_t gregorian_to_unix(uint64_t ts)
> +static int64_t gregorian_to_unix(uint64_t ts)
> {
> -   return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
> +    uint64_t offset = ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);

In general, IMO we should just use a 64bit constant here instead of the calculation.
(Not your fault obviously)

> +
> +    if (ts < offset) {
> +        errno = EOVERFLOW;
> +        return -1;

Instead of erroring out here, do you think it would be possible to
gracefully handle such negative values through changes in some other places?

> +    }
> +
> +    return ts - offset;
> }
>
> static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
> {
>     uint32_t high;
> -   uint64_t clock_reg;
> +   int64_t clock_reg;
>
>     high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
>     clock_reg = uuid->time_low | ((uint64_t) high << 32);
> @@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
>
> static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
> {
> -   uint64_t clock_reg;
> +   int64_t clock_reg;
>
>     clock_reg = uuid->time_low;
>     clock_reg <<= 16;
> --
> 2.47.3


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-13 20:04 [PATCH] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Kiran Rangoon
  2025-12-13 23:36 ` Thomas Weißschuh 
@ 2025-12-14  1:01 ` Kiran Rangoon
  2025-12-16 13:08   ` Thomas Weißschuh
  2025-12-17 11:01   ` [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Karel Zak
  1 sibling, 2 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-14  1:01 UTC (permalink / raw)
  To: util-linux; +Cc: Kiran Rangoon

gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
now use signed arithmetic to prevent unsigned wraparound.

This fixes uuidparse displaying far-future dates for historical UUIDs.

The regression test has been updated to show actual result instead of hardcoded wrong
date.

Example output:
    $ ./build/uuidparse bf2eb110-d788-1003-aa59-ce1e9e293641
Before:
    60041-08-13 16:41:36,271592-04:00
After:
    1969-12-31 19:00:00,000000-05:00

Handling negative timestamps gracefully would require broader changes, so I’ve kept this patch focused on preventing pre-1970 wraparound.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c       | 15 +++++++++++----
 tests/expected/uuid/uuidparse |  2 +-
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index c7516152b..f0d2c8f36 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,15 +60,22 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static uint64_t gregorian_to_unix(uint64_t ts)
+static int64_t gregorian_to_unix(uint64_t ts)
 {
-	return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+    const uint64_t offset = 0x01B21DD213814000ULL;
+
+    if (ts < offset) {
+        errno = EOVERFLOW;
+        return -1;
+    }
+
+    return ts - offset;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 {
 	uint32_t high;
-	uint64_t clock_reg;
+	int64_t clock_reg;
 
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
@@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 {
-	uint64_t clock_reg;
+	int64_t clock_reg;
 
 	clock_reg = uuid->time_low;
 	clock_reg <<= 16;
diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
index 9edb05e4e..0f521a760 100644
--- a/tests/expected/uuid/uuidparse
+++ b/tests/expected/uuid/uuidparse
@@ -11,7 +11,7 @@ UUID                                  VARIANT   TYPE       TIME
 00000000-0000-3000-8000-000000000000  DCE       name-based 
 00000000-0000-4000-8000-000000000000  DCE       random     
 00000000-0000-5000-8000-000000000000  DCE       sha1-based 
-00000000-0000-6000-8000-000000000000  DCE       time-v6    60038-03-11 05:36:10,955161+00:00
+00000000-0000-6000-8000-000000000000  DCE       time-v6    1970-01-01 00:00:00,000000+00:00
 00000000-0000-0000-d000-000000000000  Microsoft            
 00000000-0000-1000-d000-000000000000  Microsoft            
 00000000-0000-2000-d000-000000000000  Microsoft            
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-14  1:01 ` [PATCH v2] " Kiran Rangoon
@ 2025-12-16 13:08   ` Thomas Weißschuh
  2025-12-16 20:40     ` Kiran
  2025-12-17 11:01   ` [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Karel Zak
  1 sibling, 1 reply; 19+ messages in thread
From: Thomas Weißschuh @ 2025-12-16 13:08 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

On 2025-12-13 20:01:08-0500, Kiran Rangoon wrote:
> gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
> for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
> now use signed arithmetic to prevent unsigned wraparound.
> 
> This fixes uuidparse displaying far-future dates for historical UUIDs.
> 
> The regression test has been updated to show actual result instead of hardcoded wrong
> date.

Thanks!

> 
> Example output:
>     $ ./build/uuidparse bf2eb110-d788-1003-aa59-ce1e9e293641
> Before:
>     60041-08-13 16:41:36,271592-04:00
> After:
>     1969-12-31 19:00:00,000000-05:00
> 
> Handling negative timestamps gracefully would require broader changes,
> so I’ve kept this patch focused on preventing pre-1970 wraparound.

IMO we should to this properly. Is this something you want to work on?

> Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
> ---
>  libuuid/src/uuid_time.c       | 15 +++++++++++----
>  tests/expected/uuid/uuidparse |  2 +-
>  2 files changed, 12 insertions(+), 5 deletions(-)
> 
> diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
> index c7516152b..f0d2c8f36 100644
> --- a/libuuid/src/uuid_time.c
> +++ b/libuuid/src/uuid_time.c
> @@ -60,15 +60,22 @@
>  /* prototype to make compiler happy */
>  time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
>  
> -static uint64_t gregorian_to_unix(uint64_t ts)
> +static int64_t gregorian_to_unix(uint64_t ts)
>  {
> -	return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
> +    const uint64_t offset = 0x01B21DD213814000ULL;
> +
> +    if (ts < offset) {
> +        errno = EOVERFLOW;
> +        return -1;

The callers do not check for errors. Instead this gets converted to the
epoch only by chance.

> +    }
> +
> +    return ts - offset;
>  }
>  
>  static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
>  {
>  	uint32_t high;
> -	uint64_t clock_reg;
> +	int64_t clock_reg;
>  
>  	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
>  	clock_reg = uuid->time_low | ((uint64_t) high << 32);
> @@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
>  
>  static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
>  {
> -	uint64_t clock_reg;
> +	int64_t clock_reg;
>  
>  	clock_reg = uuid->time_low;
>  	clock_reg <<= 16;
> diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
> index 9edb05e4e..0f521a760 100644
> --- a/tests/expected/uuid/uuidparse
> +++ b/tests/expected/uuid/uuidparse
> @@ -11,7 +11,7 @@ UUID                                  VARIANT   TYPE       TIME
>  00000000-0000-3000-8000-000000000000  DCE       name-based 
>  00000000-0000-4000-8000-000000000000  DCE       random     
>  00000000-0000-5000-8000-000000000000  DCE       sha1-based 
> -00000000-0000-6000-8000-000000000000  DCE       time-v6    60038-03-11 05:36:10,955161+00:00
> +00000000-0000-6000-8000-000000000000  DCE       time-v6    1970-01-01 00:00:00,000000+00:00

If it is an error, the output should be empty.

>  00000000-0000-0000-d000-000000000000  Microsoft            
>  00000000-0000-1000-d000-000000000000  Microsoft            
>  00000000-0000-2000-d000-000000000000  Microsoft            
> -- 
> 2.47.3

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-16 13:08   ` Thomas Weißschuh
@ 2025-12-16 20:40     ` Kiran
  2025-12-16 23:21       ` Thomas Weißschuh
  0 siblings, 1 reply; 19+ messages in thread
From: Kiran @ 2025-12-16 20:40 UTC (permalink / raw)
  To: Thomas Weißschuh; +Cc: util-linux

Yes I could work on this. I'll change pre-Unix-epoch v1/v6 UUID
timestamps to be treated as an error. uuid_time_v1() and
uuid_time_v6() will detect underflow, return failure, and
__uuid_time() will propagate it by returning -1 and setting tv_sec =
tv_usec = -1, unless you have any objections.


On Tue, Dec 16, 2025 at 8:08 AM Thomas Weißschuh <thomas@t-8ch.de> wrote:
>
> On 2025-12-13 20:01:08-0500, Kiran Rangoon wrote:
> > gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
> > for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
> > now use signed arithmetic to prevent unsigned wraparound.
> >
> > This fixes uuidparse displaying far-future dates for historical UUIDs.
> >
> > The regression test has been updated to show actual result instead of hardcoded wrong
> > date.
>
> Thanks!
>
> >
> > Example output:
> >     $ ./build/uuidparse bf2eb110-d788-1003-aa59-ce1e9e293641
> > Before:
> >     60041-08-13 16:41:36,271592-04:00
> > After:
> >     1969-12-31 19:00:00,000000-05:00
> >
> > Handling negative timestamps gracefully would require broader changes,
> > so I’ve kept this patch focused on preventing pre-1970 wraparound.
>
> IMO we should to this properly. Is this something you want to work on?
>
> > Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
> > ---
> >  libuuid/src/uuid_time.c       | 15 +++++++++++----
> >  tests/expected/uuid/uuidparse |  2 +-
> >  2 files changed, 12 insertions(+), 5 deletions(-)
> >
> > diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
> > index c7516152b..f0d2c8f36 100644
> > --- a/libuuid/src/uuid_time.c
> > +++ b/libuuid/src/uuid_time.c
> > @@ -60,15 +60,22 @@
> >  /* prototype to make compiler happy */
> >  time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
> >
> > -static uint64_t gregorian_to_unix(uint64_t ts)
> > +static int64_t gregorian_to_unix(uint64_t ts)
> >  {
> > -     return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
> > +    const uint64_t offset = 0x01B21DD213814000ULL;
> > +
> > +    if (ts < offset) {
> > +        errno = EOVERFLOW;
> > +        return -1;
>
> The callers do not check for errors. Instead this gets converted to the
> epoch only by chance.
>
> > +    }
> > +
> > +    return ts - offset;
> >  }
> >
> >  static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
> >  {
> >       uint32_t high;
> > -     uint64_t clock_reg;
> > +     int64_t clock_reg;
> >
> >       high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
> >       clock_reg = uuid->time_low | ((uint64_t) high << 32);
> > @@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
> >
> >  static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
> >  {
> > -     uint64_t clock_reg;
> > +     int64_t clock_reg;
> >
> >       clock_reg = uuid->time_low;
> >       clock_reg <<= 16;
> > diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
> > index 9edb05e4e..0f521a760 100644
> > --- a/tests/expected/uuid/uuidparse
> > +++ b/tests/expected/uuid/uuidparse
> > @@ -11,7 +11,7 @@ UUID                                  VARIANT   TYPE       TIME
> >  00000000-0000-3000-8000-000000000000  DCE       name-based
> >  00000000-0000-4000-8000-000000000000  DCE       random
> >  00000000-0000-5000-8000-000000000000  DCE       sha1-based
> > -00000000-0000-6000-8000-000000000000  DCE       time-v6    60038-03-11 05:36:10,955161+00:00
> > +00000000-0000-6000-8000-000000000000  DCE       time-v6    1970-01-01 00:00:00,000000+00:00
>
> If it is an error, the output should be empty.
>
> >  00000000-0000-0000-d000-000000000000  Microsoft
> >  00000000-0000-1000-d000-000000000000  Microsoft
> >  00000000-0000-2000-d000-000000000000  Microsoft
> > --
> > 2.47.3

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-16 20:40     ` Kiran
@ 2025-12-16 23:21       ` Thomas Weißschuh
  2025-12-17 20:42         ` [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates Kiran Rangoon
                           ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Thomas Weißschuh @ 2025-12-16 23:21 UTC (permalink / raw)
  To: Kiran; +Cc: util-linux

Hi Kiran,

please reply in-line to each individual comment instead of top-posting a
single reply. It keeps the conversation understandable.

On 2025-12-16 15:40:10-0500, Kiran wrote:
> Yes I could work on this. I'll change pre-Unix-epoch v1/v6 UUID
> timestamps to be treated as an error. uuid_time_v1() and
> uuid_time_v6() will detect underflow, return failure, and
> __uuid_time() will propagate it by returning -1 and setting tv_sec =
> tv_usec = -1, unless you have any objections.

Looking at this more closely: __uuid_time() is directly exposed to users
of libuuid as uuid_time(). This means that any change of the function's
contract would break all external users and should be avoided at all
costs. Fortunately it turns out that the timestamps embedded in UUIDs
only use 60 bits. This means that the calculation can be performed in an
int64_t without any risk of over- or underflow. Please try to implement
it that way instead. It might be useful to change the signature of
gregorian_to_unix() to
"static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".
Also please perform each logical step in a dedicated commit.


Thomas

> On Tue, Dec 16, 2025 at 8:08 AM Thomas Weißschuh <thomas@t-8ch.de> wrote:
> >
> > On 2025-12-13 20:01:08-0500, Kiran Rangoon wrote:
> > > gregorian_to_unix now returns -1 and sets errno=EOVERFLOW
> > > for timestamps before the Unix epoch. uuid_time_v1 and uuid_time_v6
> > > now use signed arithmetic to prevent unsigned wraparound.
> > >
> > > This fixes uuidparse displaying far-future dates for historical UUIDs.
> > >
> > > The regression test has been updated to show actual result instead of hardcoded wrong
> > > date.
> >
> > Thanks!
> >
> > >
> > > Example output:
> > >     $ ./build/uuidparse bf2eb110-d788-1003-aa59-ce1e9e293641
> > > Before:
> > >     60041-08-13 16:41:36,271592-04:00
> > > After:
> > >     1969-12-31 19:00:00,000000-05:00
> > >
> > > Handling negative timestamps gracefully would require broader changes,
> > > so I’ve kept this patch focused on preventing pre-1970 wraparound.
> >
> > IMO we should to this properly. Is this something you want to work on?
> >
> > > Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
> > > ---
> > >  libuuid/src/uuid_time.c       | 15 +++++++++++----
> > >  tests/expected/uuid/uuidparse |  2 +-
> > >  2 files changed, 12 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
> > > index c7516152b..f0d2c8f36 100644
> > > --- a/libuuid/src/uuid_time.c
> > > +++ b/libuuid/src/uuid_time.c
> > > @@ -60,15 +60,22 @@
> > >  /* prototype to make compiler happy */
> > >  time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
> > >
> > > -static uint64_t gregorian_to_unix(uint64_t ts)
> > > +static int64_t gregorian_to_unix(uint64_t ts)
> > >  {
> > > -     return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
> > > +    const uint64_t offset = 0x01B21DD213814000ULL;
> > > +
> > > +    if (ts < offset) {
> > > +        errno = EOVERFLOW;
> > > +        return -1;
> >
> > The callers do not check for errors. Instead this gets converted to the
> > epoch only by chance.
> >
> > > +    }
> > > +
> > > +    return ts - offset;
> > >  }
> > >
> > >  static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
> > >  {
> > >       uint32_t high;
> > > -     uint64_t clock_reg;
> > > +     int64_t clock_reg;
> > >
> > >       high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
> > >       clock_reg = uuid->time_low | ((uint64_t) high << 32);
> > > @@ -80,7 +87,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
> > >
> > >  static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
> > >  {
> > > -     uint64_t clock_reg;
> > > +     int64_t clock_reg;
> > >
> > >       clock_reg = uuid->time_low;
> > >       clock_reg <<= 16;
> > > diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
> > > index 9edb05e4e..0f521a760 100644
> > > --- a/tests/expected/uuid/uuidparse
> > > +++ b/tests/expected/uuid/uuidparse
> > > @@ -11,7 +11,7 @@ UUID                                  VARIANT   TYPE       TIME
> > >  00000000-0000-3000-8000-000000000000  DCE       name-based
> > >  00000000-0000-4000-8000-000000000000  DCE       random
> > >  00000000-0000-5000-8000-000000000000  DCE       sha1-based
> > > -00000000-0000-6000-8000-000000000000  DCE       time-v6    60038-03-11 05:36:10,955161+00:00
> > > +00000000-0000-6000-8000-000000000000  DCE       time-v6    1970-01-01 00:00:00,000000+00:00
> >
> > If it is an error, the output should be empty.
> >
> > >  00000000-0000-0000-d000-000000000000  Microsoft
> > >  00000000-0000-1000-d000-000000000000  Microsoft
> > >  00000000-0000-2000-d000-000000000000  Microsoft
> > > --
> > > 2.47.3
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound
  2025-12-14  1:01 ` [PATCH v2] " Kiran Rangoon
  2025-12-16 13:08   ` Thomas Weißschuh
@ 2025-12-17 11:01   ` Karel Zak
  1 sibling, 0 replies; 19+ messages in thread
From: Karel Zak @ 2025-12-17 11:01 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

On Sat, Dec 13, 2025 at 08:01:08PM -0500, Kiran Rangoon wrote:
>  libuuid/src/uuid_time.c       | 15 +++++++++++----
>  tests/expected/uuid/uuidparse |  2 +-
>  2 files changed, 12 insertions(+), 5 deletions(-)

Submitted as a pull request to https://github.com/util-linux/util-linux/pull/3911
for CI testing.

Thanks!

    Karel

-- 
 Karel Zak  <kzak@redhat.com>
 http://karelzak.blogspot.com


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates
  2025-12-16 23:21       ` Thomas Weißschuh
@ 2025-12-17 20:42         ` Kiran Rangoon
  2025-12-17 20:59         ` Kiran Rangoon
  2025-12-18 21:31         ` Kiran Rangoon
  2 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-17 20:42 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

I revised the code in response to your feedback.

> Looking at this more closely: __uuid_time() is directly exposed to users
> of libuuid as uuid_time(). This means that any change of the function's
> contract would break all external users and should be avoided at all
> costs. 

Reversed the change there.

> Fortunately it turns out that the timestamps embedded in UUIDs
> only use 60 bits. This means that the calculation can be performed in an
> int64_t without any risk of over- or underflow. Please try to implement
> it that way instead. 

I'm using signed int64_t here as suggested.

> It might be useful to change the signature of gregorian_to_unix() to
> "static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".

I revised the code to use a struct timeval now. 

> Also please perform each logical step in a dedicated commit.

I made two commits, one for the code change and the other for tests, but
if there is a way you would perfer me to do it I could change it.

---
 libuuid/src/uuid_time.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index f0d2c8f36..293fc7e68 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,34 +60,29 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static int64_t gregorian_to_unix(uint64_t ts)
+static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
 {
-    const uint64_t offset = 0x01B21DD213814000ULL;
+	const uint64_t offset = 0x01B21DD213814000ULL;
+	int64_t t = (int64_t) ts - (int64_t) offset;
 
-    if (ts < offset) {
-        errno = EOVERFLOW;
-        return -1;
-    }
-
-    return ts - offset;
+	tv->tv_sec = t / 10000000;
+	tv->tv_usec = (t % 10000000) / 10;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 {
 	uint32_t high;
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 {
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	clock_reg = uuid->time_low;
 	clock_reg <<= 16;
@@ -95,9 +90,7 @@ static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 	clock_reg <<= 12;
 	clock_reg |= uuid->time_hi_and_version & 0xFFF;
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates
  2025-12-16 23:21       ` Thomas Weißschuh
  2025-12-17 20:42         ` [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates Kiran Rangoon
@ 2025-12-17 20:59         ` Kiran Rangoon
  2025-12-18 21:31         ` Kiran Rangoon
  2 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-17 20:59 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

I revised the code in response to your feedback.

> Looking at this more closely: __uuid_time() is directly exposed to users
> of libuuid as uuid_time(). This means that any change of the function's
> contract would break all external users and should be avoided at all
> costs. 

Reversed the change there.

> Fortunately it turns out that the timestamps embedded in UUIDs
> only use 60 bits. This means that the calculation can be performed in an
> int64_t without any risk of over- or underflow. Please try to implement
> it that way instead. 

I'm using signed int64_t here as suggested.

> It might be useful to change the signature of gregorian_to_unix() to
> "static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".

I revised the code to use a struct timeval now. 

> Also please perform each logical step in a dedicated commit.

I made two commits, one for the code change and the other for tests, but
if there is a way you would perfer me to do it I could change it.

---
 libuuid/src/uuid_time.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index f0d2c8f36..293fc7e68 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,34 +60,29 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static int64_t gregorian_to_unix(uint64_t ts)
+static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
 {
-    const uint64_t offset = 0x01B21DD213814000ULL;
+	const uint64_t offset = 0x01B21DD213814000ULL;
+	int64_t t = (int64_t) ts - (int64_t) offset;
 
-    if (ts < offset) {
-        errno = EOVERFLOW;
-        return -1;
-    }
-
-    return ts - offset;
+	tv->tv_sec = t / 10000000;
+	tv->tv_usec = (t % 10000000) / 10;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 {
 	uint32_t high;
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 {
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	clock_reg = uuid->time_low;
 	clock_reg <<= 16;
@@ -95,9 +90,7 @@ static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 	clock_reg <<= 12;
 	clock_reg |= uuid->time_hi_and_version & 0xFFF;
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates
  2025-12-16 23:21       ` Thomas Weißschuh
  2025-12-17 20:42         ` [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates Kiran Rangoon
  2025-12-17 20:59         ` Kiran Rangoon
@ 2025-12-18 21:31         ` Kiran Rangoon
  2025-12-19 11:40           ` Thomas Weißschuh
  2 siblings, 1 reply; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-18 21:31 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

I revised the code in response to your feedback.

> Looking at this more closely: __uuid_time() is directly exposed to users
> of libuuid as uuid_time(). This means that any change of the function's
> contract would break all external users and should be avoided at all
> costs. 

Reversed the change there.

> Fortunately it turns out that the timestamps embedded in UUIDs
> only use 60 bits. This means that the calculation can be performed in an
> int64_t without any risk of over- or underflow. Please try to implement
> it that way instead. 

I'm using signed int64_t here as suggested.

> It might be useful to change the signature of gregorian_to_unix() to
> "static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".

I revised the code to use a struct timeval now. 

> Also please perform each logical step in a dedicated commit.

I made two commits, one for the code change and the other for tests, but
if there is a way you would perfer me to do it I could change it.

---
 libuuid/src/uuid_time.c | 25 +++++++++----------------
 1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index f0d2c8f36..293fc7e68 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,34 +60,29 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static int64_t gregorian_to_unix(uint64_t ts)
+static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
 {
-    const uint64_t offset = 0x01B21DD213814000ULL;
+	const uint64_t offset = 0x01B21DD213814000ULL;
+	int64_t t = (int64_t) ts - (int64_t) offset;
 
-    if (ts < offset) {
-        errno = EOVERFLOW;
-        return -1;
-    }
-
-    return ts - offset;
+	tv->tv_sec = t / 10000000;
+	tv->tv_usec = (t % 10000000) / 10;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 {
 	uint32_t high;
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 {
-	int64_t clock_reg;
+	uint64_t clock_reg;
 
 	clock_reg = uuid->time_low;
 	clock_reg <<= 16;
@@ -95,9 +90,7 @@ static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 	clock_reg <<= 12;
 	clock_reg |= uuid->time_hi_and_version & 0xFFF;
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates
  2025-12-18 21:31         ` Kiran Rangoon
@ 2025-12-19 11:40           ` Thomas Weißschuh
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
                               ` (2 more replies)
  0 siblings, 3 replies; 19+ messages in thread
From: Thomas Weißschuh @ 2025-12-19 11:40 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

Hi Kiran,

On 2025-12-18 16:31:21-0500, Kiran Rangoon wrote:
> I revised the code in response to your feedback.

Thanks!

> > Looking at this more closely: __uuid_time() is directly exposed to users
> > of libuuid as uuid_time(). This means that any change of the function's
> > contract would break all external users and should be avoided at all
> > costs. 
> 
> Reversed the change there.

Your new revision is based on top of your old series.
Instead it should always be based on upstream code.
In this case the util-linux master branch.

> > Fortunately it turns out that the timestamps embedded in UUIDs
> > only use 60 bits. This means that the calculation can be performed in an
> > int64_t without any risk of over- or underflow. Please try to implement
> > it that way instead. 
> 
> I'm using signed int64_t here as suggested.
> 
> > It might be useful to change the signature of gregorian_to_unix() to
> > "static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".
> 
> I revised the code to use a struct timeval now. 

That looks good. However that refactoring should be in its own commit.
More on that below.

> > Also please perform each logical step in a dedicated commit.
> 
> I made two commits, one for the code change and the other for tests, but
> if there is a way you would perfer me to do it I could change it.

The test is a bad candidate to split out. After each commit the
repository needs to be in a consistent state, which means that the code
builds and the tests pass. As the code change breaks the existing test,
the test needs to be adapted in lockstep.

I see the following commits:

1) Switch to the simpler constant definition
2) Pass 'struct timeval' to gregorian_to_unix()
3) Fix the overflow, adapt the existing test
4) Add a hand full of additional testcases.

Also this patch now lost its useful commit message which got replaced by
our discussion. This should not happen. Each commit should explain why
it is being done.

> ---
>  libuuid/src/uuid_time.c | 25 +++++++++----------------
>  1 file changed, 9 insertions(+), 16 deletions(-)
> 
> diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
> index f0d2c8f36..293fc7e68 100644
> --- a/libuuid/src/uuid_time.c
> +++ b/libuuid/src/uuid_time.c
> @@ -60,34 +60,29 @@
>  /* prototype to make compiler happy */
>  time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
>  
> -static int64_t gregorian_to_unix(uint64_t ts)
> +static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
>  {
> -    const uint64_t offset = 0x01B21DD213814000ULL;
> +	const uint64_t offset = 0x01B21DD213814000ULL;
> +	int64_t t = (int64_t) ts - (int64_t) offset;

Whitespace corruption?

> -    if (ts < offset) {
> -        errno = EOVERFLOW;
> -        return -1;
> -    }
> -
> -    return ts - offset;
> +	tv->tv_sec = t / 10000000;
> +	tv->tv_usec = (t % 10000000) / 10;
>  }

(...)


Thomas

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow
  2025-12-19 11:40           ` Thomas Weißschuh
@ 2025-12-23 18:00             ` Kiran Rangoon
  2025-12-23 18:00               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
                                 ` (4 more replies)
  2025-12-23 18:04             ` [PATCH v4 3/4] libuuid: fix timestamp overflow for pre-1970 dates Kiran Rangoon
  2025-12-23 18:05             ` [PATCH v4 4/4] tests: correct UUID timestamp test expectations Kiran Rangoon
  2 siblings, 5 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:00 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

> On 2025-12-18 16:31:21-0500, Kiran Rangoon wrote:
> > I revised the code in response to your feedback.

> Thanks!

> > > Looking at this more closely: __uuid_time() is directly exposed to users
> > > of libuuid as uuid_time(). This means that any change of the function's
> > > contract would break all external users and should be avoided at all
> > > costs.
> >
> > Reversed the change there.
> 
> Your new revision is based on top of your old series.
> Instead it should always be based on upstream code.
> In this case the util-linux master branch.

Fixed in v4: I rebased directly on origin/master instead of building
on my previous patch series.
>
> > > Fortunately it turns out that the timestamps embedded in UUIDs
> > > only use 60 bits. This means that the calculation can be performed in an
> > > int64_t without any risk of over- or underflow. Please try to implement
> > > it that way instead.
> >
> > I'm using signed int64_t here as suggested.
> >
> > > It might be useful to change the signature of gregorian_to_unix() to
> > > "static void gregorian_to_unix(uint64_t ts, struct timeval *tv)".
> >
> > I revised the code to use a struct timeval now.
>
> That looks good. However that refactoring should be in its own commit.
> More on that below.

Fixed in v4: The refactoring is now in its own dedicated commit (patch 2/4).
>
> > > Also please perform each logical step in a dedicated commit.
> >
> > > I made two commits, one for the code change and the other for tests, but
> > > if there is a way you would perfer me to do it I could change it.
> >
> The test is a bad candidate to split out. After each commit the
> repository needs to be in a consistent state, which means that the code
> builds and the tests pass. As the code change breaks the existing test,
> the test needs to be adapted in lockstep.

Understood. In v4, the test updates are included with the code changes
that require them, maintaining repository consistency at each commit.
>
> I see the following commits:
>
> 1) Switch to the simpler constant definition
> 2) Pass 'struct timeval' to gregorian_to_unix()
> 3) Fix the overflow, adapt the existing test
> 4) Add a hand full of additional testcases.

Implemented exactly as suggested in v4.

> Also this patch now lost its useful commit message which got replaced by
> our discussion. This should not happen. Each commit should explain why
> it is being done.

Fixed in v4: All commits now have proper descriptive messages explaining
the rationale for each change.
>
> > +     const uint64_t offset = 0x01B21DD213814000ULL;
> > +     int64_t t = (int64_t) ts - (int64_t) offset;
>
> Whitespace corruption?

Fixed in v4: Proper tab indentation is used throughout.
---

This v4 patch series addresses all the feedback points above:

Kiran Rangoon (4):
  libuuid: simplify gregorian-to-unix offset calculation
  libuuid: refactor gregorian_to_unix to populate timeval directly
  libuuid: fix timestamp overflow for pre-1970 dates
  tests: correct UUID timestamp test expectations

 libuuid/src/uuid_time.c       | 15 +++++++--------
 tests/expected/uuid/uuidparse |  5 ++++-
 tests/ts/uuid/uuidparse       |  3 +++
 3 files changed, 14 insertions(+), 9 deletions(-)

-- 
2.47.3


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
@ 2025-12-23 18:00               ` Kiran Rangoon
  2025-12-23 18:00               ` [PATCH v4 2/4] libuuid: refactor gregorian_to_unix to populate timeval directly Kiran Rangoon
                                 ` (3 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:00 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

Replace complex bit-shift offset calculation with a simple constant
definition for better readability and maintainability.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index c7516152b..e2b991d74 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -62,7 +62,8 @@ time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
 static uint64_t gregorian_to_unix(uint64_t ts)
 {
-	return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+	const uint64_t offset = 0x01B21DD213814000ULL;
+	return ts - offset;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 2/4] libuuid: refactor gregorian_to_unix to populate timeval directly
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
  2025-12-23 18:00               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
@ 2025-12-23 18:00               ` Kiran Rangoon
  2025-12-23 18:03               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
                                 ` (2 subsequent siblings)
  4 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:00 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

Change function signature to take struct timeval pointer and populate
it directly, eliminating duplicate conversion code in callers.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index e2b991d74..2f7c6652c 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -60,10 +60,12 @@
 /* prototype to make compiler happy */
 time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
-static uint64_t gregorian_to_unix(uint64_t ts)
+static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
 {
 	const uint64_t offset = 0x01B21DD213814000ULL;
-	return ts - offset;
+	uint64_t clock_reg = ts - offset;
+	tv->tv_sec = clock_reg / 10000000;
+	tv->tv_usec = (clock_reg % 10000000) / 10;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
@@ -74,9 +76,7 @@ static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
 	high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
 	clock_reg = uuid->time_low | ((uint64_t) high << 32);
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
@@ -89,9 +89,7 @@ static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
 	clock_reg <<= 12;
 	clock_reg |= uuid->time_hi_and_version & 0xFFF;
 
-	clock_reg = gregorian_to_unix(clock_reg);
-	tv->tv_sec = clock_reg / 10000000;
-	tv->tv_usec = (clock_reg % 10000000) / 10;
+	gregorian_to_unix(clock_reg, tv);
 }
 
 static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
  2025-12-23 18:00               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
  2025-12-23 18:00               ` [PATCH v4 2/4] libuuid: refactor gregorian_to_unix to populate timeval directly Kiran Rangoon
@ 2025-12-23 18:03               ` Kiran Rangoon
  2025-12-23 18:22               ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Thomas Weißschuh 
  2025-12-28  8:47               ` Thomas Weißschuh
  4 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:03 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

Replace complex bit-shift offset calculation with a simple constant
definition for better readability and maintainability.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index c7516152b..e2b991d74 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -62,7 +62,8 @@ time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 
 static uint64_t gregorian_to_unix(uint64_t ts)
 {
-	return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+	const uint64_t offset = 0x01B21DD213814000ULL;
+	return ts - offset;
 }
 
 static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 3/4] libuuid: fix timestamp overflow for pre-1970 dates
  2025-12-19 11:40           ` Thomas Weißschuh
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
@ 2025-12-23 18:04             ` Kiran Rangoon
  2025-12-23 18:05             ` [PATCH v4 4/4] tests: correct UUID timestamp test expectations Kiran Rangoon
  2 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:04 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

Use int64_t arithmetic to correctly handle timestamps before Unix epoch.
This fixes the overflow that was causing UUID timestamps from 1582 to
appear as far-future dates. Update test expectations accordingly.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 libuuid/src/uuid_time.c       | 2 +-
 tests/expected/uuid/uuidparse | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index 2f7c6652c..63179fd76 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -63,7 +63,7 @@ time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
 static void gregorian_to_unix(uint64_t ts, struct timeval *tv)
 {
 	const uint64_t offset = 0x01B21DD213814000ULL;
-	uint64_t clock_reg = ts - offset;
+	int64_t clock_reg = (int64_t)(ts - offset);
 	tv->tv_sec = clock_reg / 10000000;
 	tv->tv_usec = (clock_reg % 10000000) / 10;
 }
diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
index 9edb05e4e..e44964b30 100644
--- a/tests/expected/uuid/uuidparse
+++ b/tests/expected/uuid/uuidparse
@@ -11,7 +11,7 @@ UUID                                  VARIANT   TYPE       TIME
 00000000-0000-3000-8000-000000000000  DCE       name-based 
 00000000-0000-4000-8000-000000000000  DCE       random     
 00000000-0000-5000-8000-000000000000  DCE       sha1-based 
-00000000-0000-6000-8000-000000000000  DCE       time-v6    60038-03-11 05:36:10,955161+00:00
+00000000-0000-6000-8000-000000000000  DCE       time-v6    1582-10-15 00:00:00,000000+00:00
 00000000-0000-0000-d000-000000000000  Microsoft            
 00000000-0000-1000-d000-000000000000  Microsoft            
 00000000-0000-2000-d000-000000000000  Microsoft            
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v4 4/4] tests: correct UUID timestamp test expectations
  2025-12-19 11:40           ` Thomas Weißschuh
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
  2025-12-23 18:04             ` [PATCH v4 3/4] libuuid: fix timestamp overflow for pre-1970 dates Kiran Rangoon
@ 2025-12-23 18:05             ` Kiran Rangoon
  2 siblings, 0 replies; 19+ messages in thread
From: Kiran Rangoon @ 2025-12-23 18:05 UTC (permalink / raw)
  To: util-linux; +Cc: thomas, Kiran Rangoon

Update expected timestamps for additional test UUIDs to match actual
output. These test cases provide coverage for various timestamp ranges
including pre-epoch, historical, and far-future dates.

Signed-off-by: Kiran Rangoon <kiranrangoon0@gmail.com>
---
 tests/expected/uuid/uuidparse | 3 +++
 tests/ts/uuid/uuidparse       | 3 +++
 2 files changed, 6 insertions(+)

diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
index e44964b30..61b49ef66 100644
--- a/tests/expected/uuid/uuidparse
+++ b/tests/expected/uuid/uuidparse
@@ -29,6 +29,9 @@ UUID                                  VARIANT   TYPE       TIME
 9b274c46-544a-11e7-a972-00037f500001  DCE       time-based 2017-06-18 17:21:46,544647+00:00
 1ec9414c-232a-6b00-b3c8-9f6bdeced846  DCE       time-v6    2022-02-22 19:22:22,000000+00:00
 017f22e2-79b2-7cc3-98c4-dc0c0c07398f  DCE       time-v7    2022-02-22 19:22:22,002000+00:00
+bf2eb110-d788-1003-aa59-ce1e9e293641  DCE       time-based 1586-03-19 15:05:26,3611398+00:00
+f81d4fae-7dec-11d0-a765-00a0c91e6bf6  DCE       time-based 1997-02-03 17:43:12,216875+00:00
+01234567-89ab-1def-8000-123456789abc  DCE       time-based 4764-11-18 19:35:47,841162+00:00
 5c146b14-3c52-8afd-938a-375d0df1fbf6  DCE       vendor     
 invalid-input                         invalid   invalid    invalid
 return value: 0
diff --git a/tests/ts/uuid/uuidparse b/tests/ts/uuid/uuidparse
index 2903ce56d..f131986ba 100755
--- a/tests/ts/uuid/uuidparse
+++ b/tests/ts/uuid/uuidparse
@@ -56,6 +56,9 @@ echo '00000000-0000-0000-0000-000000000000
 9b274c46-544a-11e7-a972-00037f500001
 1ec9414c-232a-6b00-b3c8-9f6bdeced846
 017f22e2-79b2-7cc3-98c4-dc0c0c07398f
+bf2eb110-d788-1003-aa59-ce1e9e293641
+f81d4fae-7dec-11d0-a765-00a0c91e6bf6
+01234567-89ab-1def-8000-123456789abc
 5c146b14-3c52-8afd-938a-375d0df1fbf6
 
 invalid-input' | $TS_CMD_UUIDPARSE >> $TS_OUTPUT 2>> $TS_ERRLOG
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
                                 ` (2 preceding siblings ...)
  2025-12-23 18:03               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
@ 2025-12-23 18:22               ` Thomas Weißschuh 
  2025-12-28  8:47               ` Thomas Weißschuh
  4 siblings, 0 replies; 19+ messages in thread
From: Thomas Weißschuh  @ 2025-12-23 18:22 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

Dec 23, 2025 19:01:03 Kiran Rangoon <kiranrangoon0@gmail.com>:

(...)

>> > This v4 patch series addresses all the feedback points above:
>
> Kiran Rangoon (4):
>   libuuid: simplify gregorian-to-unix offset calculation
>   libuuid: refactor gregorian_to_unix to populate timeval directly
>   libuuid: fix timestamp overflow for pre-1970 dates
>   tests: correct UUID timestamp test expectations
>
> libuuid/src/uuid_time.c       | 15 +++++++--------
> tests/expected/uuid/uuidparse |  5 ++++-
> tests/ts/uuid/uuidparse       |  3 +++
> 3 files changed, 14 insertions(+), 9 deletions(-)


Thanks!

For the series, given it passes CI:
Reviewed-by: Thomas Weißschuh <thomas@t-8ch.de>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow
  2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
                                 ` (3 preceding siblings ...)
  2025-12-23 18:22               ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Thomas Weißschuh 
@ 2025-12-28  8:47               ` Thomas Weißschuh
  4 siblings, 0 replies; 19+ messages in thread
From: Thomas Weißschuh @ 2025-12-28  8:47 UTC (permalink / raw)
  To: Kiran Rangoon; +Cc: util-linux

Hi Kiran,

On 2025-12-23 13:00:51-0500, Kiran Rangoon wrote:

(...)

> Kiran Rangoon (4):
>   libuuid: simplify gregorian-to-unix offset calculation
>   libuuid: refactor gregorian_to_unix to populate timeval directly
>   libuuid: fix timestamp overflow for pre-1970 dates
>   tests: correct UUID timestamp test expectations
> 
>  libuuid/src/uuid_time.c       | 15 +++++++--------
>  tests/expected/uuid/uuidparse |  5 ++++-
>  tests/ts/uuid/uuidparse       |  3 +++
>  3 files changed, 14 insertions(+), 9 deletions(-)

The series can't be applied as is. There are two 'PATCH 1/4' and  the
'In-Reply-To' headers are broken. How did you send the patches?
Please just use 'git send-email' or 'b4' [0].
Also don't make your v5 a reply to the v4, it makes things messy.
Just start a new thread.


Thomas

[0] https://b4.docs.kernel.org/en/latest/

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2025-12-28  8:47 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-13 20:04 [PATCH] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Kiran Rangoon
2025-12-13 23:36 ` Thomas Weißschuh 
2025-12-14  1:01 ` [PATCH v2] " Kiran Rangoon
2025-12-16 13:08   ` Thomas Weißschuh
2025-12-16 20:40     ` Kiran
2025-12-16 23:21       ` Thomas Weißschuh
2025-12-17 20:42         ` [PATCH v3 1/2] libuuid: Refactor UUID time conversion for pre-epoch dates Kiran Rangoon
2025-12-17 20:59         ` Kiran Rangoon
2025-12-18 21:31         ` Kiran Rangoon
2025-12-19 11:40           ` Thomas Weißschuh
2025-12-23 18:00             ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Kiran Rangoon
2025-12-23 18:00               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
2025-12-23 18:00               ` [PATCH v4 2/4] libuuid: refactor gregorian_to_unix to populate timeval directly Kiran Rangoon
2025-12-23 18:03               ` [PATCH v4 1/4] libuuid: simplify gregorian-to-unix offset calculation Kiran Rangoon
2025-12-23 18:22               ` [PATCH v4 0/4] libuuid: Fix pre-1970 UUID timestamp overflow Thomas Weißschuh 
2025-12-28  8:47               ` Thomas Weißschuh
2025-12-23 18:04             ` [PATCH v4 3/4] libuuid: fix timestamp overflow for pre-1970 dates Kiran Rangoon
2025-12-23 18:05             ` [PATCH v4 4/4] tests: correct UUID timestamp test expectations Kiran Rangoon
2025-12-17 11:01   ` [PATCH v2] libuuid: Fix pre-1970 UUID v1 timestamp wraparound Karel Zak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox