Vampire The Masquerade: Bloodlines

GlobalMemoryStatus()

Let's take a look at GlobalMemoryStatus().

void GlobalMemoryStatus(
  MEMORYSTATUS *buffer;
);

It takes one argument: the address of a MEMORYSTATUS data structure.

typedef struct _MEMORYSTATUS {
    unsigned long dwLength;
    unsigned long dwMemoryLoad;
    size_t dwTotalPhys;
    size_t dwAvailPhys;
    size_t dwTotalPageFile;
    size_t dwAvailPageFile;
    size_t dwTotalVirtual;
    size_t dwAvailVirtual;
) MEMORYSTATUS;

So we allocate some memory for one of these data structures, pass its address to GlobalMemoryStatus() and then read off the values that are set.

You can probably see the issue here. The results are stored in 32-bit variables but 64-bit Windows wants to represent stuff in 64 bits. Indeed the API documentation for GlobalMemoryStatus() explicitly states that the results cannot be relied upon and you should use GlobalMemoryStatusEx() instead.

The code in engine.dll is calling this function, getting back overflowed results which it interprets as a negative number and then (correctly) deciding that this number is less than 16Mb. Thus it (incorrectly) concludes that the system doesn't have enough RAM and dies.

We can fix that.


Jump to a section

intro | part 1: Isolating the problem | part 2: Disassembly | part 3: GlobalMemoryStatus() | part 4: The solution | part 5: Patches | part 6: Low res textures