Hi, the attached patch fixes a stack overflow in __mingw_wcstof and __mingw_wcstold.
I've also attached a small reproducer for the bug. Interestingly the bugged functions are only called if using C++ and if windows.h is included before wchar.h Regards, Tim Kosse
From 283f3f991089af0c81327cebdd9421714b2a076e Mon Sep 17 00:00:00 2001 From: Tim Kosse <tim.ko...@filezilla-project.org> Date: Tue, 18 Feb 2020 12:31:14 +0100 Subject: [PATCH] Fix stack overflow in __mingw_wcstof and __mingw_wcstold Use regular malloc instead of alloca as the caller might potentially pass a very large string exceeding the size of the stack. Signed-off-by: Tim Kosse <tim.ko...@filezilla-project.org> --- mingw-w64-crt/misc/mingw_wcstof.c | 9 ++++++++- mingw-w64-crt/misc/mingw_wcstold.c | 10 +++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/mingw-w64-crt/misc/mingw_wcstof.c b/mingw-w64-crt/misc/mingw_wcstof.c index 6cdf2e06..25f2aacd 100644 --- a/mingw-w64-crt/misc/mingw_wcstof.c +++ b/mingw-w64-crt/misc/mingw_wcstof.c @@ -12,7 +12,13 @@ __mingw_wcstof (const wchar_t * __restrict__ _Str, wchar_t ** __restrict__ _EndP size_t l, l2; l = WideCharToMultiByte(CP_UTF8, 0, _Str, -1, NULL, 0, NULL, NULL); - n = alloca (l + 1); + n = malloc (l + 1); + if (!n) + { + if (_EndPtr) + *_EndPtr = Str; + return 0.0; + } if (l != 0) WideCharToMultiByte (CP_UTF8, 0, _Str, -1, n, l, NULL, NULL); n[l] = 0; r = __mingw_strtof (n, &ep); @@ -26,6 +32,7 @@ __mingw_wcstof (const wchar_t * __restrict__ _Str, wchar_t ** __restrict__ _EndP } else if (_EndPtr) *_EndPtr = NULL; + free(n); return r; } diff --git a/mingw-w64-crt/misc/mingw_wcstold.c b/mingw-w64-crt/misc/mingw_wcstold.c index ce1ad5e0..66ee5573 100644 --- a/mingw-w64-crt/misc/mingw_wcstold.c +++ b/mingw-w64-crt/misc/mingw_wcstold.c @@ -12,7 +12,14 @@ __mingw_wcstold (const wchar_t * __restrict__ _Str, wchar_t ** __restrict__ _End size_t l, l2; l = WideCharToMultiByte(CP_UTF8, 0, _Str, -1, NULL, 0, NULL, NULL); - n = alloca (l + 1); + n = malloc (l + 1); + if (!n) + { + if (_EndPtr) + *_EndPtr = Str; + return 0.0; + } + if (l != 0) WideCharToMultiByte (CP_UTF8, 0, _Str, -1, n, l, NULL, NULL); n[l] = 0; r = __mingw_strtold (n, &ep); @@ -27,6 +34,7 @@ __mingw_wcstold (const wchar_t * __restrict__ _Str, wchar_t ** __restrict__ _End } else if (_EndPtr) *_EndPtr = NULL; + free(n); return r; } -- 2.25.1
.file "crash.cpp" .text .section .text$wcstod,"x" .linkonce discard .globl wcstod .def wcstod; .scl 2; .type 32; .endef .seh_proc wcstod wcstod: .LFB265: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue movq %rcx, 16(%rbp) movq %rdx, 24(%rbp) movq 24(%rbp), %rax movq %rax, %rdx movq 16(%rbp), %rcx call __mingw_wcstod addq $32, %rsp popq %rbp ret .seh_endproc .text .def _ZL6printfPKcz; .scl 3; .type 32; .endef .seh_proc _ZL6printfPKcz _ZL6printfPKcz: .LFB4823: pushq %rbp .seh_pushreg %rbp pushq %rbx .seh_pushreg %rbx subq $56, %rsp .seh_stackalloc 56 leaq 128(%rsp), %rbp .seh_setframe %rbp, 128 .seh_endprologue movq %rcx, -48(%rbp) movq %rdx, -40(%rbp) movq %r8, -32(%rbp) movq %r9, -24(%rbp) leaq -40(%rbp), %rax movq %rax, -96(%rbp) movq -96(%rbp), %rbx movl $1, %ecx movq __imp___acrt_iob_func(%rip), %rax call *%rax movq %rbx, %r8 movq -48(%rbp), %rdx movq %rax, %rcx call __mingw_vfprintf movl %eax, -84(%rbp) movl -84(%rbp), %eax addq $56, %rsp popq %rbx popq %rbp ret .seh_endproc .section .rdata,"dr" _ZStL19piecewise_construct: .space 1 .lcomm _ZStL8__ioinit,1,1 .def __main; .scl 2; .type 32; .endef .LC0: .ascii "crash.cpp\0" .LC1: .ascii "buf\0" .LC2: .ascii "About to call wcstod\0" .align 8 .LC3: .ascii "If you see this it did not crash, we got %lf\12\0" .text .globl main .def main; .scl 2; .type 32; .endef .seh_proc main main: .LFB6339: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $80, %rsp .seh_stackalloc 80 .seh_endprologue call __main movq $5000000, -16(%rbp) movq -16(%rbp), %rax movabsq $4611686018427387900, %rdx cmpq %rdx, %rax ja .L6 addq %rax, %rax movq %rax, %rcx call _Znay movq %rax, -24(%rbp) cmpq $0, -24(%rbp) jne .L9 jmp .L14 .L6: call __cxa_throw_bad_array_new_length .L14: movl $14, %r8d leaq .LC0(%rip), %rdx leaq .LC1(%rip), %rcx movq __imp__assert(%rip), %rax call *%rax .L9: movq $0, -8(%rbp) .L11: movq -16(%rbp), %rax subq $1, %rax cmpq %rax, -8(%rbp) jnb .L10 movq -8(%rbp), %rax leaq (%rax,%rax), %rdx movq -24(%rbp), %rax addq %rdx, %rax movw $48, (%rax) addq $1, -8(%rbp) jmp .L11 .L10: movq -16(%rbp), %rax addq %rax, %rax leaq -2(%rax), %rdx movq -24(%rbp), %rax addq %rdx, %rax movw $0, (%rax) movq $0, -40(%rbp) leaq .LC2(%rip), %rdx movq .refptr._ZSt4cerr(%rip), %rcx call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc movq .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_(%rip), %rdx movq %rax, %rcx call _ZNSolsEPFRSoS_E leaq -40(%rbp), %rdx movq -24(%rbp), %rax movq %rax, %rcx call wcstod movq %xmm0, %rax movq %rax, -32(%rbp) movsd -32(%rbp), %xmm0 movq -32(%rbp), %rax movapd %xmm0, %xmm1 movq %rax, %rdx leaq .LC3(%rip), %rcx call _ZL6printfPKcz cmpq $0, -24(%rbp) je .L12 movq -24(%rbp), %rax movq %rax, %rcx call _ZdaPv .L12: movl $0, %eax addq $80, %rsp popq %rbp ret .seh_endproc .def __tcf_0; .scl 3; .type 32; .endef .seh_proc __tcf_0 __tcf_0: .LFB6829: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue leaq _ZStL8__ioinit(%rip), %rcx call _ZNSt8ios_base4InitD1Ev nop addq $32, %rsp popq %rbp ret .seh_endproc .def _Z41__static_initialization_and_destruction_0ii; .scl 3; .type 32; .endef .seh_proc _Z41__static_initialization_and_destruction_0ii _Z41__static_initialization_and_destruction_0ii: .LFB6828: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue movl %ecx, 16(%rbp) movl %edx, 24(%rbp) cmpl $1, 16(%rbp) jne .L18 cmpl $65535, 24(%rbp) jne .L18 leaq _ZStL8__ioinit(%rip), %rcx call _ZNSt8ios_base4InitC1Ev leaq __tcf_0(%rip), %rcx call atexit .L18: nop addq $32, %rsp popq %rbp ret .seh_endproc .def _GLOBAL__sub_I_main; .scl 3; .type 32; .endef .seh_proc _GLOBAL__sub_I_main _GLOBAL__sub_I_main: .LFB6830: pushq %rbp .seh_pushreg %rbp movq %rsp, %rbp .seh_setframe %rbp, 0 subq $32, %rsp .seh_stackalloc 32 .seh_endprologue movl $65535, %edx movl $1, %ecx call _Z41__static_initialization_and_destruction_0ii nop addq $32, %rsp popq %rbp ret .seh_endproc .section .ctors,"w" .align 8 .quad _GLOBAL__sub_I_main .ident "GCC: (Rev2, Built by MSYS2 project) 9.2.0" .def __mingw_wcstod; .scl 2; .type 32; .endef .def __mingw_vfprintf; .scl 2; .type 32; .endef .def _Znay; .scl 2; .type 32; .endef .def __cxa_throw_bad_array_new_length; .scl 2; .type 32; .endef .def _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc; .scl 2; .type 32; .endef .def _ZNSolsEPFRSoS_E; .scl 2; .type 32; .endef .def _ZdaPv; .scl 2; .type 32; .endef .def _ZNSt8ios_base4InitD1Ev; .scl 2; .type 32; .endef .def _ZNSt8ios_base4InitC1Ev; .scl 2; .type 32; .endef .def atexit; .scl 2; .type 32; .endef .section .rdata$.refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, "dr" .globl .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ .linkonce discard .refptr._ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_: .quad _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ .section .rdata$.refptr._ZSt4cerr, "dr" .globl .refptr._ZSt4cerr .linkonce discard .refptr._ZSt4cerr: .quad _ZSt4cerr
#include <windows.h> // This needs to be included or it won't crash, don't ask me why #include <wchar.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <iostream> int main() { size_t num = 5000000; auto * buf = new wchar_t[num]; assert(buf); for (size_t i = 0; i < num - 1; ++i) { buf[i] = '0'; } buf[num - 1] = 0; wchar_t * end = 0; std::cerr << "About to call wcstod" << std::endl; double d = wcstod(buf, &end); printf("If you see this it did not crash, we got %lf\n", d); delete[] buf; return 0; }
_______________________________________________ Mingw-w64-public mailing list Mingw-w64-public@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/mingw-w64-public