From 7081a525902dcc4acf4f00a2a773b927e86ccbb7 Mon Sep 17 00:00:00 2001
From: "Rob Swindell (in GitKraken)" <rob@synchro.net>
Date: Sat, 11 Mar 2023 17:16:37 -0800
Subject: [PATCH] Fix mysterious double overflow issue in parse_byte_count()

It's possible that some values (e.g. "16384P") exceed the storage (count of
bytes) of a 64-bit integer, and such values were causing floating point
exceptions when running sbbsctrl.exe, e.g.
Faulting application name: sbbsctrl.exe, version: 3.20.0.0, time stamp:
0x00000000
Faulting module name: gdi32full.dll, version: 10.0.19041.2604, time stamp:
0x2b5302d5
Exception code: 0xc0000090

but interesting (and perhaps a clue), not with sbbs.exe.

Anyway, this added range checking, limiting the maximum value to INT64_MAX
(after division by unit, though there was no division-unit in the problem
case, the "min_dspace" value parsing in scfglib2.c). Using conditional/ternary
return statement had the same floating point exception occurrences, so this
if-statement shouldn't be removed/changed/optimized!

I suspect this has something to do with mix of Borland and MSVC run-time libs
and perhaps different expectations or setups with regards to floating point
exceptions. I did notice that when stepping through read_file_cfg(), I would
get different return values for the same call to iniGetBytes() depending on
whether it was initiated from sbbsctrl.exe (built with C++Builder) or
sbbs.dll (built with MSVC).

Thanks to Codefenix for providing the sample file.ini file that demonstrated
the issue. This problem would've been very hard to root-cause otherwise!
---
 src/xpdev/genwrap.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/src/xpdev/genwrap.c b/src/xpdev/genwrap.c
index cc7d151c50..c95dbcac0d 100644
--- a/src/xpdev/genwrap.c
+++ b/src/xpdev/genwrap.c
@@ -279,7 +279,11 @@ int64_t parse_byte_count(const char* str, ulong unit)
 				break;
 		}
 	}
-	return((int64_t)(unit>1 ? (bytes/unit):bytes));
+	if(unit > 1)
+		bytes /= unit;
+	if(bytes < 0 || bytes > INT64_MAX)
+		return INT64_MAX;
+	return (int64_t)bytes;
 }
 
 static const double one_pebibyte = 1024.0*1024.0*1024.0*1024.0*1024.0;
-- 
GitLab