Live data from Hacker News

How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

cookieplmonster.github.io

171–180 of 315 posts

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#171
post #10

This is the kind of thing I'd expect from Raymond Chen - which is extremely high praise! I'm glad they tracked it down even further to figure out exactly why.

Or randomascii. A freaking legend (although he had a heart braking streak of bad events ... I wish him the best)

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#172

Am I the only one to be annoyed by this...? while (this->m_fBladeAngle > 6.2831855) { this->m_fBladeAngle = this->m_fBladeAngle - 6.2831855; } Like, "let's just write a while loop that could turn into an infinite loop coz I'm too lazy to do a division"

I want to assume that the GTA developers did this hack because it was faster than floating point division on the Playstation 2 or something.

But knowing they were able to they were able to blow up loading GTA5 by 5 minutes by just parsing json with sscanf, I don't have much hope.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#173

Am I the only one to be annoyed by this...? while (this->m_fBladeAngle > 6.2831855) { this->m_fBladeAngle = this->m_fBladeAngle - 6.2831855; } Like, "let's just write a while loop that could turn into an infinite loop coz I'm too lazy to do a division"

I'm willing to bet it was was done for performance reasons, subtraction is cheaper than float point division. Probably the compiler also has some tricks to optimize this further.

There is absolutely no way this could turn into an infinite loop. It could underflow, but for that to happen angle would have to be less than the 2*pi, therefore exiting the loop.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#174

Am I the only one to be annoyed by this...? while (this->m_fBladeAngle > 6.2831855) { this->m_fBladeAngle = this->m_fBladeAngle - 6.2831855; } Like, "let's just write a while loop that could turn into an infinite loop coz I'm too lazy to do a division"

Long shot, but maybe if the value is small, then this loop could be faster than division.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#176

IMHO, if something isn’t part of the contract, it should be randomized. Eg if iteration order of maps isn’t guaranteed in your language, then your language should go out of its way to randomize it. Otherwise, you end up with brittle code: code that works fine until it doesn’t.

Aren't you just creating another contract? Users might write code that depends on it being random.

Maybe it would be good to change all non promised things between releases. So that such unwritten rules never become something users rely upon.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#177
post #141

Earlier quoted context omitted.

You can pay for those features in debug mode or in chaos monkey mode. It's okay to continue to not pay for them in release mode. Heck, Rust has this approach when it comes to handling integer overflow - fully checked in debug mode, silent wraparound in release mode.

In Ada you can pay for integer overflow checks (runtime) if you want to. With Ada SPARK you can prove that your code does not contain integer overflows so that you don't need runtime checks.

And you can disable these checks with a flag when it comes to Ada, and yeah, with SPARK, none of it happens at runtime.

Check the table at https://docs.adacore.com/spark2014-docs/html/ug/en/usage_sce..., look for "SPARK builds on the strengths of Ada to provide even more guarantees statically rather than dynamically.".

More reading:

https://docs.adacore.com/spark2014-docs/html/ug/en/tutorial....

https://learn.adacore.com (many books for learning Ada and SPARK) available in PDF, EPUB, and HTML format.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#178

Am I the only one to be annoyed by this...? while (this->m_fBladeAngle > 6.2831855) { this->m_fBladeAngle = this->m_fBladeAngle - 6.2831855; } Like, "let's just write a while loop that could turn into an infinite loop coz I'm too lazy to do a division"

Long shot, but maybe if the value is small, then this loop could be faster than division.

If the code runs every frame, it's probably always small and does just one iteration once in a while when it wraps over the value.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#179
post #164
post #144

Earlier quoted context omitted.

> The compiler has no way of knowing that the memory would be undefined Yes it would. -fsanitize=address does a bunch of instrumentation - it allocates shadow memory to keep track of what main memory is defined, and it checks every read and write address against the shadow memory. It is a combination of compile-time instrumentation and run-time checking. And yes, it is expensive, so it should be used for debugging an…

You both may be right. It could be that ASAN is not instrumenting scanf (or some other random standard lib function). Though since 2015, it certainly has been. https://github.com/google/sanitizers/issues/108 The simpler policy of "don't allow unintialized locals when declared" would also have caught it with the tools available when the game was made (though a bit ham-fisted).

The problem is that after calling scanf(), the number of variables that are defined is a variable number. For example:

    int x, y, z;
    int n = scanf("%d %d %d", &x, &y, &z);
At compile time, you can make no inferences about which of x, y, and z are defined, because that depends on the returned value n. There are many ways to branch out from this.

One is to insist on definite assignment - so if we cannot prove all of them are always assigned, then we can treat them as "possibly undefined" and err out.

Another way is to avoid passing references and instead allow multiple returns, like Python (this is pseudocode):

    x, y, z = scanf("%d %d %d")
In that case, if the hypothetical `scanf()` returns a tuple that is less than 3 elements or more than 3 elements, then the unpacking will fail at run time and crash exactly at that line.

Another way is like Java, which insists that the return value is a scalar, so it can't do what C and Python can do. This can be painful on the programmer, of course.

Re: How a 20 year old bug in GTA San Andreas surfaced in Windows 11 24H2

#180
post #144

Earlier quoted context omitted.

The compiler has no way of knowing that the memory would be undefined, not unless it somehow can verify the data file. The most I think it can do is flag the program for not checking the return value of scanf, but even that is unlikely to be true since the program probably was checking for end of file which is also in the return value. It was failing to check the number of matched parameters. This is the kind of erro…

> The compiler has no way of knowing that the memory would be undefined Yes it would. -fsanitize=address does a bunch of instrumentation - it allocates shadow memory to keep track of what main memory is defined, and it checks every read and write address against the shadow memory. It is a combination of compile-time instrumentation and run-time checking. And yes, it is expensive, so it should be used for debugging an…

I tried this with clang ASAN. Nothing happens. It won't catch this bug. ASAN detects the presence of incorrect behavior, not the absence of correct behavior.

There's no use-after-free, use-after-return, use-after-scope, or OOB access here. It's a case of "an allocated stack variable is dynamically read without being initialized only in a runtime case," which afaik no standard analyzer will catch.

The best way to identify this would be to require all locals to be initialized as a matter of policy (very unlikely to fly in a games studio, especially back then, due to the perceived performance overhead) or to debug with a form of stack initialization enabled, like "-ftrivial-auto-var-init=pattern" which while it doesn't catch the issue statically, does make it appear pretty quickly in QA (I tested).

Post reply on HN