Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expect POSIX compatible vsnprintf. #8788

Merged
merged 1 commit into from Sep 3, 2014

Conversation

Projects
None yet
2 participants
@BevapDin
Copy link
Contributor

commented Sep 2, 2014

Fixes #8784

This seems to be a mingw problem. I can reproduce this with the windows-SDL and windows-curses build using wine on linux. It does not happen with the linux build.

My guess: vstring_format (output.cpp) uses vsnprintf to format the string. That function is supposed to return -1 if the buffer it to small (see http://msdn.microsoft.com/en-us/library/1kt27hek.aspx), in that case the buffer is increased and the function is called again until it succeeds. The function returns a number >= 0 only when the buffer was large enough.

The linux/POSIX version of that function returns the size of the buffer that is required to print the formatted string (even when the current buffer size if to small).

It's a bit unclear to me which version mingw uses. There is code in output.cpp that handles both versions (depending on whether it is compiled for window or not). It also depends on localization: with -DLOCALIZE (which seems to be the default), vsnprintf is actually libintl_vsnprintf (coming from libintl, which is part of gettext, it may or may not be POSIX compatible, that apparently depends on its input, see http://lists.gnu.org/archive/html/bug-gnu-utils/2007-02/msg00058.html).


The problem boils down to this scenario:

The code assumes vsnprintf is the windows version (returns -1 when the buffer is too small).

The initial buffer size is 1024 bytes, large enough for most strings. The text with the recipes is probably larger, therefor the first call to vsnprintf fails - the windows version would return -1, the buffer would be increased, the function called again. This does not happen.

Instead vsnprintf seems to be the POSIX version and returns the required buffer size (for example 1040). The program assumes that formatting was successful (any value >= 0 indicates success) and that the buffer was large enough. It copies the content of the buffer, but it assumes that the returned value is the length of the string in the buffer (in this case 1040). But the buffer is only 1024 bytes large, so it reads data from outside of the buffer.


I've added a simple check for this scenario: if vsnprintf returns a number >= 0, the number is compared to the buffer size. If it is less than (or equal to) the buffer size, it is assumed the formatted string has been successfully written in the buffer (and the buffer was large enough) and the buffers content is returned. This works with both windows and POSIX version of vsnprintf.

If the returned number is greater than the buffer size, it is assumed that this is the required buffer size, the buffer is enlarged to that size and vsnprintf is called again. This indicates a POSIX version of vsnprintf. The windows version would not return a number greater than the buffer size.

If the returned value is negative, it is assumed that the buffer was not large enough, the buffer is enlarged (its size if doubled), and vsnprintf is called again. This is the same behavior as before.

Expect POSIX compatible vsnprintf.
Detect when the return value indicates the required buffer size and use that buffer size.
Or if the return value is simply -1, guess another (bigger) buffer size.

@KA101 KA101 self-assigned this Sep 3, 2014

@KA101 KA101 merged commit 26bdad6 into CleverRaven:master Sep 3, 2014

1 check passed

default
Details

@BevapDin BevapDin deleted the BevapDin:crash-in-string-format branch Sep 3, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.