Repository navigation
Stack corruption with snprintf(3) and format %hu #5130
Copy link
Copy link
Closed
Milestone
Description
PAL tests fall down with
src/pal/tests/palsuite/c_runtime/vsprintf/test11/test11.c
with the following example call:
DoNumTest("foo %hu", 0xFFFF, "foo 65535");
There is stack corruption here:
https://github.com/dotnet/coreclr/blob/master/src/pal/src/cruntime/printfcpp.cpp#L1822
else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
{
// Convert explicitly from int to short to get
// correct sign extension for shorts on all systems.
int n;
short s;
n = va_arg(ap, int);
s = (short) n;
TempInt = snprintf(BufferPtr, TempCount, TempBuff, s); // <--- here
}
(gdb) list
1814 // Convert explicitly from int to short to get
1815 // correct sign extension for shorts on all systems.
1816 int n;
1817 short s;
1818
1819 n = va_arg(ap, int);
1820 s = (short) n;
1821
1822 TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
1823 }
(gdb) n
1820 s = (short) n;
(gdb) p n
$8 = 65535
(gdb) n
1822 TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
(gdb) p s
$9 = -1
(gdb) p BufferPtr
$10 = (LPSTR) 0x7f7fffffd924 ""
(gdb) p BufferPtr-1
$11 = (CHAR *) 0x7f7fffffd923 " "
(gdb) p BufferPtr-2
$12 = (CHAR *) 0x7f7fffffd922 "o "
(gdb) p BufferPtr-3
$13 = (CHAR *) 0x7f7fffffd921 "oo "
(gdb) p BufferPtr-4
$14 = (CHAR *) 0x7f7fffffd920 "foo "
(gdb) p TempBuff
$15 = "%hu\000\177\177\000\000\006\362E\000\000\000\000\000\000\222\377\367\177\177\000\000\000P�\367\177\177\000\000�\322\377\377\177\177\000\000\006\362E\000\000\000\000\000�\322\377\377\177\177\000\000\000P�\367\177\177\000\000\020\323\377\377\177\177\000\000\006\362E\000\000\000\000\000��D\000\000\000\000\000\377\232N\000\000\000\000\000\000X\377\367\016\000\000\000\000P�\367\177\177\000\000@\323\377\377\177\177\000\000\006\362E\000\000\000\000\000\004\323\377\377\177\177\000\000L2�\367\177\177\000\000\000X\377\367\177\177\000\000��N\000\000\000\000\000\000X\377\367\177\177\000\000L2�\367\177\177\000\000\020\323\377\377\001\000\000\000�a�\367\177\177\000\000 \323\377\377\177\177\000\000"...
(gdb) n
Breakpoint 2, CoreVsnprintf (pthrCurrent=0x7f7ff7b05000, Buffer=0x7f7fffffd924 "", Count=2147483643, Format=0x7f7fffffd240 "%hu", aparg=0x7f7fffffcdb8)
at /tmp/pkgsrc-tmp/wip/coreclr-git/work/coreclr/src/pal/src/cruntime/printfcpp.cpp:1819
1819 n = va_arg(ap, int);
(gdb)
I'm trying to determine what's going on.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
krytarowski commentedon Feb 17, 2016
Debugging on
NetBSD 7.99.26krytarowski commentedon Feb 17, 2016
With the following patch I reduce the number of falling down tests (
alloca(3) fixes for NetBSD locally committed) from ~63 to 7.krytarowski commentedon Feb 17, 2016
PAL test results with the above patch applied.
krytarowski commentedon Feb 17, 2016
Now.. I don't understand what's and why wrong. Why
va_arg(3) corrupts stack only for"%hd"/"%hu", while all other (including"%h") combinations work...Have you got an idea @janvorli or @jkotas ?
Thank you for enlightening me.
janvorli commentedon Feb 17, 2016
Looking at the function that converts the formatting string, the "%h" seems to be replaced incorrectly just by "%", but even %h alone is an incorrect specifier. So it is not used in the formatting and that's likely the reason why it doesn't crash while the "%hd" / "%hu" do.
Could you please paste here the whole formatting string passed as the "format" parameter to the CoreVfwprintf function when the crash happens?
krytarowski commentedon Feb 17, 2016
It crashes with the following example formatting strings:
"foo %hu""foo %hd"krytarowski commentedon Feb 17, 2016
While it works with
"foo %h","foo %d", etc. Please see the number of passed tests and their coverage.janvorli commentedon Feb 17, 2016
@krytarowski I have stepped through the code on Linux and I have not noticed anything suspicious, except for one thing that depending on the va_arg definition in the new clang might cause a problem. The code at line 1819 is asking for int parameter, while the actual one is short. Although I believe that shorts should be passed as 32 bit values on AMD64 too (and in this case, it should be passed in a register, based on the AMD64 ABI document), who knows what the va_arg does in such case.
Could you please disassemble the CoreVsnprintf function in the gdb using disass /m and post it somewhere so that I can compare it with the code from the clang 3.5 on Linux? The va_arg stuff is inlined, so it should be sufficient to spot potential culprit.
krytarowski commentedon Feb 17, 2016
Thank you @janvorli for help! Generally shorter types are promoted to longer.
stdarg(3) on NetBSD says:I'm suspecting a compiler bug.. I will try to generate assembly for comparison. I wasn't able to reproduce this issue with a small code example. Nothing interesting resides in
.ifiles.krytarowski commentedon Feb 17, 2016
I've added
nopmarks, just in case of optimization to close the region between twovolatilefragments.The result:
krytarowski commentedon Feb 17, 2016
@janvorli if you need assembly for full function, please let me know.
krytarowski commentedon Feb 17, 2016
@janvorli if you need assembly for full function, please let me know.
janvorli commentedon Feb 17, 2016
@krytarowski I would really need the whole disass of the function, ideally without the added nops. I have tried to compare your piece of code with my one, it seems equivalent except for slightly different instruction ordering and registers allocations at few places and some RBP offsets. Having the whole function disass would enable me to figure out whether the offsets are wrong or they are caused just by some data structure being larger on NetBSD.
krytarowski commentedon Feb 17, 2016
OK, Just a sec.
krytarowski commentedon Feb 17, 2016
I've disassembled
CoreVsnprintfthis way:gdb -batch -ex 'file ./bin/obj/NetBSD.x64.Debug/src/pal/tests/palsuite/c_runtime/vsprintf/test11/paltest_vsprintf_test11' -ex 'disassemble CoreVsnprintf'The result is accessible here:
ftp://ftp.netbsd.org/pub/NetBSD/misc/kamil/coreclr-disasm-1.txt
26 remaining items
janvorli commentedon Feb 18, 2016
I have thought we already do the trick for the _vsnprintf, but now I can see we don't. So that should work.
krytarowski commentedon Feb 18, 2016
Thanks! I will mimic
PAL_printf.krytarowski commentedon Feb 18, 2016
I will give it a try.. just need to fix dotnet/coreclr#3219 as it broke on NetBSD...
Thank you.
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL
Fix issue unveiled on NetBSD: Add PAL__vsnprintf shadow in PAL