archive mirror
 help / color / mirror / Atom feed
* [PATCH] xsize_t: avoid implementation defined behavior when len < 0
@ 2021-05-18 15:03 Jonathan Nieder
  2021-05-19  1:36 ` Junio C Hamano
  0 siblings, 1 reply; 3+ messages in thread
From: Jonathan Nieder @ 2021-05-18 15:03 UTC (permalink / raw)
  To: git; +Cc: Ramsay Jones

The xsize_t helper aims to safely convert an off_t to a size_t,
erroring out when a file offset is too large to fit into a memory
address.  It does this by using two casts:

	size_t size = (size_t) len;
	if (len != (off_t) size)
		... error out ...

On a platform with sizeof(size_t) < sizeof(off_t), this check is safe
and correct.  The first cast truncates to a size_t by finding the
remainder modulo SIZE_MAX+1 (see C99 section Signed and
unsigned integers) and the second promotes to an off_t, meaning the
result is true if and only if len is representable as a size_t.

On other platforms, this two-casts strategy still works well (always
succeeds) for len >= 0.  But for len < 0, when the first cast succeeds
and produces SIZE_MAX + 1 + len, the resulting value is too large to
be represented as an off_t, so the second cast produces implementation
defined behavior.  In practice, it is likely to produce a result of
true despite len not being representable as size_t.

Simplify by replacing with a more straightforward check: compare len
to the relevant bounds and then cast it.

In practice, this is not likely to come up since typical callers use
nonnegative len.  Still, it's helpful to handle this case to make the
behavior easy to reason about.

Historical note: the original bounds-checking in 46be82dfd0 (xsize_t:
check whether we lose bits, 2010-07-28) did not produce this
implementation-defined behavior, though it still did not handle
negative offsets.  It was not until 73560c793a (git-compat-util.h:
xsize_t() - avoid -Wsign-compare warnings, 2017-09-21) introduced the
double cast that the implementation-defined behavior was triggered.

Signed-off-by: Jonathan Nieder <>

This is *not* -rc material; it's just something I noticed and figured
I would send it before I forget (among other benefits, this helps us
kick the tires on the release candidate by having patches to work

Thoughts welcome, as always.


 git-compat-util.h | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/git-compat-util.h b/git-compat-util.h
index a508dbe5a3..20318a0aac 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -986,11 +986,9 @@ static inline char *xstrdup_or_null(const char *str)
 static inline size_t xsize_t(off_t len)
-	size_t size = (size_t) len;
-	if (len != (off_t) size)
+	if (len < 0 || len > SIZE_MAX)
 		die("Cannot handle files this big");
-	return size;
+	return (size_t) len;
 __attribute__((format (printf, 3, 4)))

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

end of thread, other threads:[~2021-05-19  1:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-18 15:03 [PATCH] xsize_t: avoid implementation defined behavior when len < 0 Jonathan Nieder
2021-05-19  1:36 ` Junio C Hamano
2021-05-19  1:52   ` [PATCH v2] " Jonathan Nieder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).