Не используйте дети malloc в Windows 10
От: _NN_ www.nemerleweb.com
Дата: 10.03.18 15:08
Оценка: 95 (15) +1
Как оказывается начиная с Windows 10 Creators Update (1703) функция HeapAlloc не потокобезопасна, а следовательно и malloc.

malloc()/free() in several threads crahes on Windows — what's wrong?

В *никсе такого бы не случилось
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re: Не используйте дети malloc в Windows 10
От: okman Беларусь https://searchinform.ru/
Дата: 10.03.18 19:12
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Как оказывается начиная с Windows 10 Creators Update (1703) функция HeapAlloc не потокобезопасна, а следовательно и malloc.


_NN>malloc()/free() in several threads crahes on Windows — what's wrong?


_NN>В *никсе такого бы не случилось


Как страшно жить теперь

Кто-нибудь пробовал у себя предложенный тест в VS2015/2017?
У меня за 20 минут ни разу так и не упало (Windows 10'1709, VS2015 update 3)...
Re[2]: Не используйте дети malloc в Windows 10
От: _NN_ www.nemerleweb.com
Дата: 11.03.18 08:59
Оценка:
Здравствуйте, okman, Вы писали:

O>Кто-нибудь пробовал у себя предложенный тест в VS2015/2017?

O>У меня за 20 минут ни разу так и не упало (Windows 10'1709, VS2015 update 3)...

Упало за минуты две. windows 10 1709. VS 2017.6. Релиз 64-бит. 8 ядер.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 12.03.18 21:27
Оценка:
O>>Кто-нибудь пробовал у себя предложенный тест в VS2015/2017?
O>>У меня за 20 минут ни разу так и не упало (Windows 10'1709, VS2015 update 3)...
_NN>Упало за минуты две. windows 10 1709. VS 2017.6. Релиз 64-бит. 8 ядер.
А выложите свою ucrtbase.dll, койчо гляну.
Но врядли многопоточность тут виновата — там накрываются крит. секцией операции с хипом и все. А если они по какой то причине не накрываются — был бы пипец всему.
Скорее всего дело в определенной хитрой последовательности маллок-фри. Можно интереса ради накрыть извне критической секцией каждый малок и фри, и если будет воспроизводиться (возможно, пореже), то добавить логику, которая бы както быстренько записывала последовательность операций, чтобы потом проиграть их в одном потоке и получить 100% крэш. А потом уже можно думать и про эксплоит
ЗЫ У меня самого десятки нет, так что все вышеописанное — в ваших руках
Как много веселых ребят, и все делают велосипед...
Отредактировано 12.03.2018 22:11 ononim . Предыдущая версия . Еще …
Отредактировано 12.03.2018 21:48 ononim . Предыдущая версия .
Отредактировано 12.03.2018 21:47 ononim . Предыдущая версия .
Отредактировано 12.03.2018 21:46 ononim . Предыдущая версия .
Re[4]: Не используйте дети malloc в Windows 10
От: Videoman Россия https://hts.tv/
Дата: 13.03.18 12:44
Оценка:
Здравствуйте, ononim, Вы писали:

Могу только подтвердить что приведенный код действительно падает под 10-кой под VS2013 и VS2017. Более того, если malloc заменить на new, то тоже падает, так как new внутри себя зовет malloc.

O>Но врядли многопоточность тут виновата — там накрываются крит. секцией операции с хипом и все. А если они по какой то причине не накрываются — был бы пипец всему.

O>Скорее всего дело в определенной хитрой последовательности маллок-фри. Можно интереса ради накрыть извне критической секцией каждый малок и фри, и если будет воспроизводиться (возможно, пореже), то добавить логику, которая бы както быстренько записывала последовательность операций, чтобы потом проиграть их в одном потоке и получить 100% крэш. А потом уже можно думать и про эксплоит
O>ЗЫ У меня самого десятки нет, так что все вышеописанное — в ваших руках

Если сделать внешний лок, то падения прекращаются.

O>А выложите свою ucrtbase.dll, койчо гляну.


А зачем? Вот стек вызовов при падении:
> ntdll.dll!RtlAllocateHeap()
msvcr120.dll!malloc(unsigned int size) Line 92 + 0x3b bytes C
msvcr120.dll!operator new(unsigned int size) Line 59 + 0x8 bytes C++

В релизе ucrtbase.dll не вызывается. В дебаге вызывается и там лок стоит. И, естественно, не падает.
Re: Не используйте дети malloc в Windows 10
От: T4r4sB Россия  
Дата: 13.03.18 12:51
Оценка:
Здравствуйте, _NN_, Вы писали:

Как хорошо, что я предусмотрительный, и в своих проектах "для себя" просто выделяю с самого начала большой блок, а потом внутри него работаю ручным аллокатором.
Re[5]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 13.03.18 13:25
Оценка:
O>>А выложите свою ucrtbase.dll, койчо гляну.
V>А зачем? Вот стек вызовов при падении:
>> ntdll.dll!RtlAllocateHeap()
V> msvcr120.dll!malloc(unsigned int size) Line 92 + 0x3b bytes C
V> msvcr120.dll!operator new(unsigned int size) Line 59 + 0x8 bytes C++
Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.
А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри

V>В релизе ucrtbase.dll не вызывается. В дебаге вызывается и там лок стоит. И, естественно, не падает.

По ссылке в начальном посте есть стеки с ucrtbase
Вложите тогда свою msvcr120.dll
Как много веселых ребят, и все делают велосипед...
Отредактировано 13.03.2018 13:32 ononim . Предыдущая версия . Еще …
Отредактировано 13.03.2018 13:31 ononim . Предыдущая версия .
Re[6]: Не используйте дети malloc в Windows 10
От: Videoman Россия https://hts.tv/
Дата: 13.03.18 13:41
Оценка:
Здравствуйте, ononim, Вы писали:

O>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.

O>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри

Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?

V>>В релизе ucrtbase.dll не вызывается. В дебаге вызывается и там лок стоит. И, естественно, не падает.

O>По ссылке в начальном посте есть стеки с ucrtbase
O>Вложите тогда свою msvcr120.dll

Так эта же msvcr120.dll не падает не под 10-кой. А где GetProcessHeap() и то что он возвращает инициализируется?
Re[7]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 13.03.18 13:45
Оценка:
O>>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.
O>>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
Я и так скажу — GetProcessHeap куча потокобезопасная. Надо ставить бряку на RtlAllocateHeap и смотреть чему равен rdx.


O>>По ссылке в начальном посте есть стеки с ucrtbase

O>>Вложите тогда свою msvcr120.dll
V>Так эта же msvcr120.dll не падает не под 10-кой. А где GetProcessHeap() и то что он возвращает инициализируется?
Она в PEB, инициализируется на запуске процесса в LdrpInitialize.
Как много веселых ребят, и все делают велосипед...
Re[7]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 13.03.18 13:49
Оценка:
O>>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.
O>>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
ладненько, тогда эксперимент 2: все тоже самое, но вместо malloc — HeapAlloc(GetProcessHeap(), 0, 4096) а вместо freee — HeapFree(GetProcessHeap(), 0, ...)
Как много веселых ребят, и все делают велосипед...
Re[8]: Не используйте дети malloc в Windows 10
От: Videoman Россия https://hts.tv/
Дата: 13.03.18 15:10
Оценка:
Здравствуйте, ononim, Вы писали:

O>>>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.

O>>>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
O>ладненько, тогда эксперимент 2: все тоже самое, но вместо malloc — HeapAlloc(GetProcessHeap(), 0, 4096) а вместо freee — HeapFree(GetProcessHeap(), 0, ...)

К сожалению пока не могу продолжить эксперимент, так как чудесным образом оно перестало падать. Не падает ни c malloc, ни c new... никак... чудеса
Re[9]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 13.03.18 15:12
Оценка:
O>>>>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>>>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>>>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
O>>ладненько, тогда эксперимент 2: все тоже самое, но вместо malloc — HeapAlloc(GetProcessHeap(), 0, 4096) а вместо freee — HeapFree(GetProcessHeap(), 0, ...)
V>К сожалению пока не могу продолжить эксперимент, так как чудесным образом оно перестало падать. Не падает ни c malloc, ни c new... никак... чудеса
мб сработал appcompatibility и включил эту приблуду: https://msdn.microsoft.com/en-us/library/windows/desktop/dd744764(v=vs.85).aspx
попробуйте запустить под другим именем ехешника
Как много веселых ребят, и все делают велосипед...
Re[10]: Не используйте дети malloc в Windows 10
От: Videoman Россия https://hts.tv/
Дата: 13.03.18 15:35
Оценка:
Здравствуйте, ononim, Вы писали:

O>мб сработал appcompatibility и включил эту приблуду: https://msdn.microsoft.com/en-us/library/windows/desktop/dd744764(v=vs.85).aspx

O>попробуйте запустить под другим именем ехешника

Нет, такая служба не работает — проверил. Проблема просто перестала воспроизводится.
Re[11]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 13.03.18 16:20
Оценка: :))) :))) :))) :)
O>>мб сработал appcompatibility и включил эту приблуду: https://msdn.microsoft.com/en-us/library/windows/desktop/dd744764(v=vs.85).aspx
O>>попробуйте запустить под другим именем ехешника
V>Нет, такая служба не работает — проверил. Проблема просто перестала воспроизводится.
они просто через телеметрию увидели что тебя это беспокоит и отключили этот бэкдор
Как много веселых ребят, и все делают велосипед...
Re[11]: Не используйте дети malloc в Windows 10
От: _NN_ www.nemerleweb.com
Дата: 14.03.18 14:09
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Здравствуйте, ononim, Вы писали:


O>>мб сработал appcompatibility и включил эту приблуду: https://msdn.microsoft.com/en-us/library/windows/desktop/dd744764(v=vs.85).aspx

O>>попробуйте запустить под другим именем ехешника

V>Нет, такая служба не работает — проверил. Проблема просто перестала воспроизводится.


Попробуйте в 64-битной версии.
Падает гораздо быстрее чем 32-бит.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[8]: Не используйте дети malloc в Windows 10
От: _NN_ www.nemerleweb.com
Дата: 14.03.18 14:12
Оценка:
Здравствуйте, ononim, Вы писали:

O>>>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.

O>>>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
O>ладненько, тогда эксперимент 2: все тоже самое, но вместо malloc — HeapAlloc(GetProcessHeap(), 0, 4096) а вместо freee — HeapFree(GetProcessHeap(), 0, ...)

Падает в 64-бит:
> ntdll.dll!RtlpLowFragHeapAllocFromContext() Unknown
ntdll.dll!RtlpAllocateHeapInternal() Unknown
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Не используйте дети malloc в Windows 10
От: _NN_ www.nemerleweb.com
Дата: 14.03.18 14:18
Оценка:
Здравствуйте, ononim, Вы писали:

O>>>А выложите свою ucrtbase.dll, койчо гляну.

V>>А зачем? Вот стек вызовов при падении:
>>> ntdll.dll!RtlAllocateHeap()
V>> msvcr120.dll!malloc(unsigned int size) Line 92 + 0x3b bytes C
V>> msvcr120.dll!operator new(unsigned int size) Line 59 + 0x8 bytes C++
O>Затем что HeapCreate имеет флаг 'HEAP_NO_SERIALIZE' если использовать который — получается не потокобезопасная по дефолту куча.
O>А еще такой же флаг имеет HeapAlloc — то есть если вызвать HeapAlloc на потокобезопасной куче, передав ему HEAP_NO_SERIALIZE — то вызов будет не потокобезопасный.
O>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри

WinDbg говорит что все кучи безопасные:

— 23d36f40000
HEAP_GROWABLE
— 23d34e80000
HEAP_CLASS_8
— 23d37170000
HEAP_GROWABLE HEAP_CLASS_1
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[9]: Не используйте дети malloc в Windows 10
От: ononim  
Дата: 14.03.18 16:19
Оценка: :)
O>>>>Так что анализ кода позволит понять это косяк ucrtbase (использование таких флагов) или поломали чтото внутри
V>>>Про флаги я в курсе. У меня у самого эта идея появилась в голове. Куча там берется из GetProcessHeap(). Как у нее посмотреть флаги создания?
O>>ладненько, тогда эксперимент 2: все тоже самое, но вместо malloc — HeapAlloc(GetProcessHeap(), 0, 4096) а вместо freee — HeapFree(GetProcessHeap(), 0, ...)
_NN>Падает в 64-бит:
>> ntdll.dll!RtlpLowFragHeapAllocFromContext() Unknown
_NN> ntdll.dll!RtlpAllocateHeapInternal() Unknown
жжжжопауть до чего наделла страну довел
Как много веселых ребят, и все делают велосипед...
Re: Не используйте дети malloc в Windows 10
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.03.18 21:13
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Как оказывается начиная с Windows 10 Creators Update (1703) функция HeapAlloc не потокобезопасна, а следовательно и malloc.


_NN>malloc()/free() in several threads crahes on Windows — what's wrong?


_NN>В *никсе такого бы не случилось


Это типа все — приехали, конечная?

Windows 10 Pro (1709, патчи до 3 марта 2018 года)

VS2017 15.6.2

  Опции компилятора — по умолчанию
/Yu"stdafx.h" /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /sdl /Fd"x64\Release\vc141.pdb" /Zc:inline /fp:precise /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oi /MD /FC /Fa"x64\Release\" /EHsc /nologo /Fo"x64\Release\" /Fp"x64\Release\ConsoleApplication1.pch" /diagnostics:classic

Запустил "x64 release" на 10-ядерном (6950x) — упало и под отладчиком и при запуске из под cmd.exe. Падает достаточно быстро.

  Стек падения под отладчиком
     ntdll.dll!RtlpAllocateHeap()    Unknown
     ntdll.dll!RtlpAllocateHeapInternal()    Unknown
     ntdll.dll!RtlpAllocateUserBlockFromHeap()    Unknown
     ntdll.dll!RtlpAllocateUserBlock()    Unknown
     ntdll.dll!RtlpLowFragHeapAllocFromContext()    Unknown
     ntdll.dll!RtlpAllocateHeapInternal()    Unknown
     ucrtbase.dll!_malloc_base()    Unknown
>    ConsoleApplication1.exe!task() Line 15    C++
     [Inline Frame] ConsoleApplication1.exe!std::_Invoker_functor::_Call(void(*)() &&) Line 232    C++
     [Inline Frame] ConsoleApplication1.exe!std::invoke(void(*)() &&) Line 232    C++
     [Inline Frame] ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Execute(std::tuple<void (__cdecl*)(void)> &) Line 240    C++
     [Inline Frame] ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > > *) Line 247    C++
     ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Go() Line 232    C++
     ConsoleApplication1.exe!std::_Pad::_Call_func(void * _Data) Line 211    C++
     ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void * __ptr64)>()    Unknown
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[2]: Не используйте дети malloc в Windows 10
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 19.03.18 21:37
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:

КД>Запустил "x64 release" на 10-ядерном (6950x) — упало и под отладчиком и при запуске из под cmd.exe. Падает достаточно быстро.


  Переписал код, чтобы напрямую использовались HeapCreate, HeapDestroy, HeapAlloc, HeapFree
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <conio.h>
#include <Windows.h>

using namespace std;

#define MAX_THREADS 100

HANDLE g_HEAP=NULL;

void task(void)
{
    while (true)
    {
        char *buffer;
        buffer = (char *)HeapAlloc(g_HEAP,0,4096);
        if (buffer == NULL)
        {
            cout << "malloc error" << endl;
        }
        HeapFree(g_HEAP,0,buffer);
    }
}

int main(int argc, char** argv)
{
    g_HEAP=::HeapCreate(0,8*1024*1024,0);

    if(!g_HEAP)
    {
     cout<<L"HeapCreate failed: "<<::GetLastError()<<endl;
     return -1;
    }

    thread some_threads[MAX_THREADS];

    for (int i = 0; i < MAX_THREADS; i++)
    {
        some_threads[i] = thread(task);
    }

    for (int i = 0; i < MAX_THREADS; i++)
    {
        some_threads[i].join();
    }

    if (!::HeapDestroy(g_HEAP))
    {
     cout<<L"HeapDestroy failed: "<<::GetLastError()<<endl;
    }

    _getch();
    return 0;
}

Падает скатина! И под cmd.exe и под отладчиком!

Exception thrown at 0x00007FFFC9F7678A (ntdll.dll) in ConsoleApplication1.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.


  Стек падения.
>    ntdll.dll!RtlFreeHeap()    Unknown
     ConsoleApplication1.exe!task() Line 24    C++
     [Inline Frame] ConsoleApplication1.exe!std::_Invoker_functor::_Call(void(*)() &&) Line 232    C++
     [Inline Frame] ConsoleApplication1.exe!std::invoke(void(*)() &&) Line 232    C++
     [Inline Frame] ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Execute(std::tuple<void (__cdecl*)(void)> &) Line 240    C++
     [Inline Frame] ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > > *) Line 247    C++
     ConsoleApplication1.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl*)(void)>,std::default_delete<std::tuple<void (__cdecl*)(void)> > > >::_Go() Line 232    C++
     ConsoleApplication1.exe!std::_Pad::_Call_func(void * _Data) Line 211    C++
     ucrtbase.dll!thread_start<unsigned int (__cdecl*)(void * __ptr64)>()    Unknown
     kernel32.dll!BaseThreadInitThunk()    Unknown
     ntdll.dll!RtlUserThreadStart()    Unknown

Надо с CreateThread/beginthread еще попробовать.
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.