pawn-lang / compiler

Pawn compiler for SA-MP with bug fixes and new features - runs on Windows, Linux, macOS
Other
307 stars 72 forks source link

Fix preprocessor hanging indefinitely when processing #import directive on WSL #733

Closed JLWalsh closed 3 months ago

JLWalsh commented 3 months ago

TL;DR

This PR fixes a bug on WSL (and potentially Linux) where the preprocessor is stuck in an indefinite loop. I've setup a repository to repro the issue which can be found here: https://github.com/JLWalsh/pawncc-wsl-bug-demo

What is the bug?

When processing includes, the preprocessor checks if the path is not a directory by calling stat() and then checking !S_ISDIR() on the result as we only want to load files. The current implementation does not check the result of stat(), which can fail. When this happens, the results of stat() cannot be trusted and the !S_ISDIR() check passes even when the path is a directory.

This causes the preprocessor to open a file descriptor pointing to a directory instead of a file. The compiler will then get stuck in a loop in the preprocess() function as readline() returns an empty line without moving the parser forward. This happens because readline() attempts to read the directory as a file, which naturally does not work.

By adding the result check on stat(), we can prevent the compiler from hanging indefinitely. However, the underlying issue causing stat() to fail is not fixed. In my testing I found that stat() fails with errno=75 (EOVERFLOW) because of a storage discrepancy caused by 32 bit executables running on a 64 bit machine. More details on this error can be found in the stat() manpage error section. The recommended fix is to define the _FILE_OFFSET_BITS flag which worked on my machine

Why doesn't this happen on Windows?

This is down to a difference in behaviour of fgets() between Windows and WSL. The readline() function loads the included file line by line using fgets(). When calling fgets() with a directory on Linux, a file handle is returned. On Windows, I found that it would simply return NULL, which kept the compiler running as expected

Testing

I've tested the compiler on the sample project I've linked and it works after applying this bugfix. I'm not sure what other means of testing this project has, but I'd be happy to run more tests if need be

Which issue(s) this PR fixes:

Not sure if this has been reported before

Fixes #

Additional Documentation:

Repro repo: https://github.com/JLWalsh/pawncc-wsl-bug-demo