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)
|
if(range>RAND_MAX)
|
||||||
{
|
{
|
||||||
UINT max = (UINT)GServer->round(sqrt((double)range));
|
UINT max = (UINT)GServer->round(sqrt((double)range));
|
||||||
UINT num1 = init+int(max*rand()/(RAND_MAX + 1.0));
|
// NOTE: multiply in double first -- on Linux RAND_MAX is 2^31-1 (vs.
|
||||||
UINT num2 = init+int(max*rand()/(RAND_MAX + 1.0));
|
// Windows' 15-bit 32767), so "max*rand()" done in integer arithmetic
|
||||||
UINT num3 = init+int(max*rand()/(RAND_MAX + 1.0));
|
// 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;
|
UINT res = (num1 * num2)+num3;
|
||||||
return res>range?range:res;
|
return res>range?range:res;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UINT ranum = init+int(range*rand()/(RAND_MAX + 1.0));
|
UINT ranum = init+int((double)range*rand()/(RAND_MAX + 1.0));
|
||||||
return ranum;
|
return ranum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3162,18 +3162,18 @@ bool CWorldServer::pakCraft( CPlayer* thisclient, CPacket* P )
|
|||||||
int lowest = thisclient->Attr->Con/ 10 + 17;
|
int lowest = thisclient->Attr->Con/ 10 + 17;
|
||||||
int highest = thisclient->Attr->Con / 10 + 70;
|
int highest = thisclient->Attr->Con / 10 + 70;
|
||||||
int range = (highest - lowest) + 1;
|
int range = (highest - lowest) + 1;
|
||||||
item.durability = lowest+int(range*rand()/(RAND_MAX + 1.0));
|
item.durability = lowest+int((double)range*rand()/(RAND_MAX + 1.0));
|
||||||
|
|
||||||
// stats randomizer
|
// stats randomizer
|
||||||
int changeofstatslow = thisclient->Attr->Sen / 13 + 10;
|
int changeofstatslow = thisclient->Attr->Sen / 13 + 10;
|
||||||
int changeofstatshigh = thisclient->Attr->Sen / 13 + 50;
|
int changeofstatshigh = thisclient->Attr->Sen / 13 + 50;
|
||||||
int changeofstatsrange = (changeofstatshigh-changeofstatslow)+1;
|
int changeofstatsrange = (changeofstatshigh-changeofstatslow)+1;
|
||||||
if (changeofstatslow+int(changeofstatsrange*rand()/(RAND_MAX + 1.0)) > 50)
|
if (changeofstatslow+int((double)changeofstatsrange*rand()/(RAND_MAX + 1.0)) > 50)
|
||||||
{
|
{
|
||||||
int statslowget = 1;
|
int statslowget = 1;
|
||||||
int statshighget = 256;
|
int statshighget = 256;
|
||||||
int setstatrange=(statshighget-statslowget)+1;
|
int setstatrange=(statshighget-statslowget)+1;
|
||||||
item.stats = statslowget + int(setstatrange*rand()/(RAND_MAX + 1.0));
|
item.stats = statslowget + int((double)setstatrange*rand()/(RAND_MAX + 1.0));
|
||||||
item.appraised = 1;
|
item.appraised = 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
Reference in new issue
Block a user