runtime: throw if a timespec64 can't be converted to a timespec32

Firstly;
As far as I know we do not ever have a value inside a timespec
that does not fit into a timespec32, we only ever use it
for time durations which will continue to fit in timespec32
after Y2038 since it is relative.

In the case that assumption is wrong
I would like to be told about it.

Secondly;
Assuming this is false and we are storing datetimes in theses
timespecs, I do not know what to do if we are trying to convert
it to a 32bits timespec.

Since the correct thing we are doing is to always use the 64bits
codepath when it is available, thus if we try to convert such
too big timespec to 32bits means the host Linux doesn't support
the 64bits codepaths.

Then I think it's a there is no good solution situation,
and I think crashing is better than continuing with a corrupted
(due to truncation) timespec32.

Change-Id: I4456ff9d96d85eb3da38a938d699a6e5e99f3844
Reviewed-on: https://go-review.googlesource.com/c/go/+/751342
Auto-Submit: Jorropo <jorropo.pgm@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Jorropo 2026-03-04 10:11:05 +01:00 committed by Gopher Robot
parent 0d54be530b
commit 4e06ed21ac

View file

@ -27,11 +27,11 @@ func futex(addr unsafe.Pointer, op int32, val uint32, ts *timespec, addr2 unsafe
if use64bitsTimeOn32bits {
return futex_time64(addr, op, val, ts, addr2, val3)
}
// Downgrade ts.
var ts32 timespec32
var pts32 *timespec32
if ts != nil {
ts32.setNsec(ts.tv_sec*1e9 + int64(ts.tv_nsec))
ts32 = ts.mustDowncastToTimespec32()
pts32 = &ts32
}
return futex_time32(addr, op, val, pts32, addr2, val3)
@ -53,16 +53,29 @@ func timer_settime(timerid int32, flags int32, new, old *itimerspec) int32 {
var new32, old32 *itimerspec32
if new != nil {
newts.it_interval.setNsec(new.it_interval.tv_sec*1e9 + int64(new.it_interval.tv_nsec))
newts.it_value.setNsec(new.it_value.tv_sec*1e9 + int64(new.it_value.tv_nsec))
newts.it_interval = new.it_interval.mustDowncastToTimespec32()
newts.it_value = new.it_value.mustDowncastToTimespec32()
new32 = &newts
}
if old != nil {
oldts.it_interval.setNsec(old.it_interval.tv_sec*1e9 + int64(old.it_interval.tv_nsec))
oldts.it_value.setNsec(old.it_value.tv_sec*1e9 + int64(old.it_value.tv_nsec))
oldts.it_interval = old.it_interval.mustDowncastToTimespec32()
oldts.it_value = old.it_value.mustDowncastToTimespec32()
old32 = &oldts
}
return timer_settime32(timerid, flags, new32, old32)
}
// mustDowncastToTimespec32 converts a 64-bit timespec to a 32-bit
// timespec and throws if the value cannot be represented in 32 bits.
//
//go:nosplit
func (ts timespec) mustDowncastToTimespec32() (r timespec32) {
r.tv_sec = int32(ts.tv_sec)
if ts.tv_sec != int64(r.tv_sec) {
throw("timespec64 value cannot be represented in timespec32")
}
r.tv_nsec = ts.tv_nsec
return
}