[tor-bugs] #31567 [Applications/Tor Browser]: NS_tsnprintf() does not handle %s correctly on Windows
Tor Bug Tracker & Wiki
blackhole at torproject.org
Fri Aug 30 09:43:38 UTC 2019
#31567: NS_tsnprintf() does not handle %s correctly on Windows
-------------------------------------------------+-------------------------
Reporter: mcs | Owner: gk
Type: defect | Status:
| needs_review
Priority: Very High | Milestone:
Component: Applications/Tor Browser | Version:
Severity: Critical | Resolution:
Keywords: ff68-esr, tbb-9.0-must-alpha, | Actual Points:
TorBrowserTeam201908R |
Parent ID: | Points:
Reviewer: | Sponsor:
-------------------------------------------------+-------------------------
Changes (by pospeselr):
* keywords: ff68-esr, tbb-9.0-must-alpha, TorBrowserTeam201908 =>
ff68-esr, tbb-9.0-must-alpha, TorBrowserTeam201908R
* status: needs_information => needs_review
Comment:
**tldr** there's a patch at the end
Did some digging on this tonight just for fun. According to this post on
stack overflow ( https://stackoverflow.com/a/18283757 ) libstdc++ is built
with the {{{__USE_MINGW_ANSI_STDIO}}} define, so calls to the printf and
wprintf function families will use the expected format string behaviour
found on non-windows platforms. Apparently libstdc++ depends on the ANSI
stdio behavior so it's toggled on.
The following program will output differently depending on which headers
you use (C or C++) even if you build with mingw g++
{{{
#ifdef USE_STDC
#include <stdio.h>
#include <wchar.h>
#else
#include <cstdio>
#include <cwchar>
##endif
int main()
{
printf("1: %s\n", "ansi format, ansi string");
printf("2: %S\n", L"ansi format, wide string");
wprintf(L"3: %s\n", "wide format, ansi string");
wprintf(L"4: %S\n", L"wide format, wide string");
fflush(stdout);
}
}}}
----
If you build with the C headers, you get the following output (wine on
linux):
{{{
1: ansi format, ansi string
2: ansi format, wide string
3: 4: w
}}}
This it the output you would expect if you built with vcs given
Microsoft's printf format specifiers ( https://docs.microsoft.com/en-
us/cpp/c-runtime-library/format-specification-syntax-printf-and-wprintf-
functions?view=vs-2019 )
The first two prints work as expected, but the next two fail:
3 is expecting the string to be a wide character string, but it
encounters an ansi string. I don't know what this ansi string encodes as
wide string, but it would seem wprintf gives up trying to print it. For
shits and giggles, if we replace 3's ansi string with
{{{"w\0i\0d\0e\0\0"}}} it prints out 'wide' to the console.
4 is expecting an ansi string but gets a wide string, so it prints the
ansi 'w', finds a NULL byte and treats it as a terminator, only printing
out 'w'.
----
If you build with the C++ headers (or if you build with the C headers and
add {{{#define __USE_MINGW_ANSI_STDIO 1}}} before including {{{stdio.h}}},
you get the following output:
{{{
1: ansi format, ansi string
2: ansi format, wide string
3: wide format, ansi string
4: wide format, wide string
}}}
Which is as one would expect I think. Undefining
{{{__USE_MINGW_ANSI_STDIO}}} or redifining it to 0 does not seem to
reverse the effect when using the C++ headers.
----
However, we probably shouldn't go fucking around with this define because
who what else depends on this behaviour to work. Instead, we should
replace the _vsnwprintf call with StringCchVPrintfW. As StringCchVPrintfW
has no expectation of conforming to ANSI C string format specifiers, it
can instead ignore the {{{__USE_MINGW_ANSI_STDIO}}} define and always
conform the Microsoft's specifiers. The following example builds and runs
using the Microsoft formats:
{{{
#include <windows.h>
#include <strsafe.h>
#include <iostream>
using namespace std;
int main()
{
char abuffer[1024];
wchar_t wbuffer[1024];
StringCchPrintfA(abuffer, 1024, "1: %s\n", "ansi format, ansi
string"); // small S for ansi
cout << abuffer;
StringCchPrintfA(abuffer, 1024, "2: %S\n", L"ansi format, wide
string"); // big S for wide
cout << abuffer;
cout << flush;
StringCchPrintfW(wbuffer, 1024, L"3 : %S\n", "wide format, ansi
string"); // big S for ansi
wcout << wbuffer;
StringCchPrintfW(wbuffer, 1024, L"4': %s\n", L"wide format, wide
string"); // small S for wide
wcout << wbuffer;
wcout << flush;
}
}}}
----
This patch replaces the _vsnwprintf with StringCchVPrintfExW from
strsafe.h, a windows specific function and as such implements Microsoft's
format-string specifiers. The new implementation of mywcsprintf has the
same outputs and retval as the old for a handful of test-cases.
**tor-browser patch**:
https://gitweb.torproject.org/user/richard/tor-
browser.git/commit/?h=bug_31567
--
Ticket URL: <https://trac.torproject.org/projects/tor/ticket/31567#comment:6>
Tor Bug Tracker & Wiki <https://trac.torproject.org/>
The Tor Project: anonymity online
More information about the tor-bugs
mailing list