Fix core RNG collapsing to ~0-1 on Linux due to integer overflow
CWorldServer::RandNumber (and three inlined copies of the same pattern in worldpackets.cpp's item-refine code) computed "range*rand()" in integer arithmetic before dividing by (RAND_MAX + 1.0). On Windows RAND_MAX is 32767 (15-bit), so this never overflowed. On Linux/glibc RAND_MAX is 2147483647 (2^31-1), so "range*rand()" overflows a 32-bit UINT for the vast majority of rand() outputs, wrapping to a small value -- the division by ~2^31 then collapses the result to ~0 or 1 almost always, regardless of the requested range. This made every percentage-based roll in the game (item drop selection, refine durability/stats, and anything else using RandNumber) behave as if called with range 1-2 instead of the real range, which is why item drops effectively never triggered post-port. Cast to double before the multiply so it can't overflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
560f6a968f
commit
f053a06920
2 files changed
+11
-7
No files matched your search
@@ -1048,15 +1048,19 @@ UINT CWorldServer::RandNumber( UINT init, UINT range, UINT seed )
|
||||
if(range>RAND_MAX)
|
||||
{
|
||||
UINT max = (UINT)GServer->round(sqrt((double)range));
|
||||
UINT num1 = init+int(max*rand()/(RAND_MAX + 1.0));
|
||||
UINT num2 = init+int(max*rand()/(RAND_MAX + 1.0));
|
||||
UINT num3 = init+int(max*rand()/(RAND_MAX + 1.0));
|
||||
// NOTE: multiply in double first -- on Linux RAND_MAX is 2^31-1 (vs.
|
||||
// Windows' 15-bit 32767), so "max*rand()" done in integer arithmetic
|
||||
// before dividing overflows UINT for nearly every rand() result,
|
||||
// collapsing the output to ~0-1 regardless of range/max.
|
||||
UINT num1 = init+int((double)max*rand()/(RAND_MAX + 1.0));
|
||||
UINT num2 = init+int((double)max*rand()/(RAND_MAX + 1.0));
|
||||
UINT num3 = init+int((double)max*rand()/(RAND_MAX + 1.0));
|
||||
UINT res = (num1 * num2)+num3;
|
||||
return res>range?range:res;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT ranum = init+int(range*rand()/(RAND_MAX + 1.0));
|
||||
UINT ranum = init+int((double)range*rand()/(RAND_MAX + 1.0));
|
||||
return ranum;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user