Заводим Git for Windows под ReactOS

    Всем доброго времени суток! image


    Меня зовут Станислав, и я люблю писать код. Это моя первая статья на Хабре, на написание которой меня сподвигло несколько факторов:


    • Недостаток статей технического плана в хабе ReactOS
    • Недавнее возвращение Geektimes на Хабр
    • Возможность собрать ReactOS в ReactOS
    • Довольно интересный случай исправления проблемы в ReactOS, в котором я принимал непосредственное участие

    Позвольте представить вам виновников данного торжества (исправленного бага, который мешал запуску Git в ReactOS) — французский разработчик Hermès Bélusca-Maïto (далее просто Гермес, с ником hbelusca), и собственно я (с ником x86corez).


    История начинается со следующих сообщений из IRC-канала разработчиков ReactOS:


    Jun 03 18:52:56 <hbelusca> Anybody want to work on some small problem? If so, can someone figure out why this problem https://jira.reactos.org/browse/CORE-12931 happens on ReactOS? :D
    Jun 03 18:53:13 <hbelusca> That would help having a good ROS self-hosting system with git support.
    Jun 03 18:53:34 <hbelusca> (the git assertion part only).

    Разбор полётов


    Поскольку на данный момент ReactOS нацелен на совместимость с Windows Server 2003, в качестве подопытного кролика был выбран Git версии 2.10.0 — последней, в которой заявлена поддержка Windows XP и 2003.


    Тестирование осуществлялось в командной строке ReactOS, внешние симптомы проблемы были довольно неоднозначными. Например, при запуске git без указания дополнительных аргументов, он без каких-либо проблем выводил справочную информацию в консоль. Но стоило попробовать git clone или хотя бы git --version, в большинстве случаев консоль совсем ничего не выводила, либо изредка показывала битое сообщение с assertion:


    git.exe clone -v "https://github.com/minoca/os.git" "C:\Documents and Settings\Administrator\Bureau\minocaos"
    
    A s s e r t i o n   f a i l e d ! 
    
    P r o g r a m :   C : \ P r o g r a m   F i l e s \ G i t \ m i n g w 3 2 \ b i n \ g i t . e x e 
    F i l e :   e x e c _ c m d . c ,   L i n e   2 3 
    E x p r e s s i o n :   a r g v 0 _ p a t h 
    
    This application has requested the Runtime to terminate in an unusual way.
    Please contact the application's support team for more information.

    Исследованию проблемы очень поспособствовало, что клиент git — с открытым исходным кодом, и найти строку, на которой возникало исключение, не составило большого труда: https://github.com/git-for-windows/git/blob/4cde6287b84b8f4c5ccb4062617851a2f3d7fc78/exec_cmd.c#L23


    char *system_path(const char *path)
    {
        /* вырезано */
    
    #ifdef RUNTIME_PREFIX
        assert(argv0_path); // проблема возникает здесь
        assert(is_absolute_path(argv0_path));
    
        /* вырезано */
    #endif
    
        strbuf_addf(&d, "%s/%s", prefix, path);
        return strbuf_detach(&d, NULL);
    }

    А значение переменной argv0_path задавалось данным участком кода:


    const char *git_extract_argv0_path(const char *argv0)
    {
        const char *slash;
    
        if (!argv0 || !*argv0)
            return NULL;
    
        slash = find_last_dir_sep(argv0);
    
        if (slash) {
            argv0_path = xstrndup(argv0, slash - argv0);
            return slash + 1;
        }
    
        return argv0;
    }

    После выяснения этих деталей я отписался на IRC-канале:


    Jun 03 19:04:36 <x86corez> hbelusca: https://github.com/git-for-windows/git/blob/4cde6287b84b8f4c5ccb4062617851a2f3d7fc78/exec_cmd.c#L23
    Jun 03 19:04:41 <x86corez> assertion is here
    Jun 03 19:04:57 <hbelusca> yes I know, I've seen the code yesterday. The question is why it's FALSE on ROS but TRUE on Windows.
    Jun 03 19:06:02 <x86corez> argv0_path = xstrndup(argv0, slash - argv0);
    Jun 03 19:06:22 <x86corez> xstrndup returns NULL %-)
    Jun 03 19:06:44 <hbelusca> ok, so what's the values of argv0 and slash on windows vs. on ROS? :P
    Jun 03 19:08:48 <x86corez> good question!

    Имя переменной как бы намекает, что значение было получено из argv[0] — обычно в нулевом индексе этого массива содержится строка с именем команды, которой была вызвана текущая программа. Но в дальнейшем всё оказалось не столь очевидно...


    Jun 03 20:15:21 <x86corez> hbelusca: surprise... git uses its own xstrndup implementation
    Jun 03 20:15:35 <x86corez> so I can't simply hook it xD
    Jun 03 20:15:56 <hbelusca> well, with such a name "xstrndup" it's not surprising it's its own implementation
    Jun 03 20:16:04 <x86corez> probably I would need an user-mode debugger... like OllyDbg
    Jun 03 20:16:09 <hbelusca> that's everything but standardized function.
    Jun 03 20:16:24 <hbelusca> x86corez: ollydbg should work on ROS.
    Jun 03 20:16:30 <mjansen> what are you breaking today?
    Jun 03 20:16:44 <x86corez> mjansen: https://jira.reactos.org/browse/CORE-12931
    Jun 03 20:16:51 <hbelusca> (of course if you also are able to compile that git with symbols and all the stuff, it would be very nice)

    Переход к активным действиям


    После этого я принял решение собрать git из исходников, чтобы было проще "на лету" выводить значения интересующих переменных прямо в консоль. Мной был выбран данный пошаговый мануал, и для сборки совместимой версии я выбрал эту ветку: https://github.com/git-for-windows/git/tree/shears/v2.10.0-rc2


    Настройка тулчейна mingw32 прошла без проблем, и я запустил сборку. Но в подобных пошаговых мануалах зачастую есть недокументированные подводные камни, и на один из них я сразу же наткнулся:


    image


    Путём проб и ошибок, а также пользуясь подсказками из зала (IRC-канала) все проблемы компиляции удалось решить. Если кто-то захочет повторить мой путь, делюсь готовым диффом для успешной сборки: https://pastebin.com/ZiA9MaKt


    Дабы исключить влияние множества функций при инициализации, я решил вывести несколько отладочных сообщений прямо в начале функции main(), которая в случае git расположена в файле common-main.c:


    int main(int argc, const char **argv)
    {
        /*
         * Always open file descriptors 0/1/2 to avoid clobbering files
         * in die().  It also avoids messing up when the pipes are dup'ed
         * onto stdin/stdout/stderr in the child processes we spawn.
         */
        //DebugBreak();
        printf("sanitize_stdfds(); 1\n");
        sanitize_stdfds();
    
        printf("git_setup_gettext(); 1\n");
        git_setup_gettext();
    
        /*
         * Always open file descriptors 0/1/2 to avoid clobbering files
         * in die().  It also avoids messing up when the pipes are dup'ed
         * onto stdin/stdout/stderr in the child processes we spawn.
         */
        printf("sanitize_stdfds(); 2\n");
        sanitize_stdfds();
    
        printf("git_setup_gettext(); 2\n");
        git_setup_gettext();
    
        printf("before argv[0] = %s\n", argv[0]);
        argv[0] = git_extract_argv0_path(argv[0]);
        printf("after argv[0] = %s\n", argv[0]);
    
        restore_sigpipe_to_default();
        printf("restore_sigpipe_to_default(); done\n");
    
        return cmd_main(argc, argv);
    }

    Вывод получился следующий:


    C:\>git --version
    sanitize_stdfds(); 1
    git_setup_gettext(); 1
    sanitize_stdfds(); 2
    git_setup_gettext(); 2
    before argv[0] = git
    after argv[0] = git
    restore_sigpipe_to_default(); done
    
    A s s e r t i o n   f a i l e d ! 
    (часть вырезана, совпадает с ранее приведённой)

    Казалось бы, всё нормально, argv[0] таким и должен быть. Пришла идея погонять git внутри отладчика, например в OllyDbg, но что-то пошло не так...


    Jun 04 01:54:46 <sanchaez> now please try gdb/ollydbg in ROS
    Jun 04 01:58:11 <sanchaez> you have gdb in RosBE
    Jun 04 01:58:20 <sanchaez> just in case :p
    Jun 04 01:59:45 <x86corez> ollydbg says "nope" with MEMORY_MANAGEMENT bsod
    Jun 04 02:00:07 <x86corez> !bc 0x0000001A
    Jun 04 02:00:08 <hTechBot> KeBugCheck( MEMORY_MANAGEMENT );
    Jun 04 02:00:13 <hbelusca> :/
    Jun 04 02:00:49 <sanchaez> welp
    Jun 04 02:00:56 <sanchaez> you only have one option now :D

    И вот тут sanchaez подсказал отличную идею, которая пролила свет на многое!


    image


    Исключения больше не возникало, и git успешно печатал свой номер версии.


    Jun 04 02:23:40 <x86corez> it prints!
    Jun 04 02:23:44 <x86corez> but only in gdb
    Jun 04 02:23:53 <hbelusca> oh
    Jun 04 02:24:00 <hbelusca> C:\git/git.exe
    Jun 04 02:24:13 <hbelusca> I wonder whether it's the same in windows, or not.

    Дело сдвинулось с мёртвой точки, и я решил попробовать по-разному запускать git в командной строке, и не прогадал!


    image


    Проблема явно была в том, что git ожидал полный путь в командной строке. Тогда я решил проверить, какие данные будут выведены в Windows. Результаты меня немного удивили.


    image


    В переменной argv[0] почему-то был полный путь к приложению.


    Jun 05 23:01:44 <hbelusca> x86corez: can you try to run git also by not using cmd.exe?
    Jun 05 23:02:05 <hbelusca> (to exclude the possibility it's cmd that doesn't call Createprocess with a complete path)
    Jun 05 23:02:09 <hbelusca> while I think it should...
    Jun 05 23:02:30 <x86corez> not using cmd... moment
    Jun 05 23:02:55 <hbelusca> x86corez: alternatively, on windows, try starting git using our own cmd.exe :)

    Гермес предложил проверить, может быть проблема где-то в командной строке ReactOS...


    image


    Но это оказалось не так. Вариант с оболочкой cmd отпадает.


    Jun 05 23:04:38 <x86corez> ROS cmd is not guilty
    Jun 05 23:07:57 <hbelusca> If there was a possibility to consult the received path, before looking at the contents of argvs... ?
    Jun 05 23:08:30 <x86corez> dump contents of actual command line?
    Jun 05 23:08:39 <hbelusca> yeah
    Jun 05 23:09:39 <hbelusca> The thing you retrieve using GetCommandLineW
    Jun 05 23:10:03 <hbelusca> (which is, after simplifications, basically : NtCurrentPeb()->ProcessParameters->CommandLine )
    Jun 05 23:10:59 <hbelusca> Also I was thinking it could be a side-effect of having (or not having) git path into the env-vars....
    Jun 05 23:12:17 <x86corez> hbelusca, command line is "git  --version"
    Jun 05 23:12:34 <hbelusca> Always?
    Jun 05 23:12:39 <x86corez> Yes, even on Windows
    Jun 05 23:15:13 <hbelusca> ok but then it would be nice if these different results are at least the same on Windows and on ROS, so that we can 100% exclude problems outside of msvcrt.

    Теперь оставалось лишь протестировать библиотеку msvcrt.dll из ReactOS под Windows. Я попробовал положить файл в той же директории, где лежал git.exe, но это не помогло. Марк посоветовал способ с файлом .local:


    Jun 05 22:59:01 <mjansen> x86corez: add .local file next to msvcrt.dll ;)
    Jun 05 22:59:47 <mjansen> exename.exe.local
    Jun 05 23:00:17 <x86corez> just an empty file?
    Jun 05 23:00:21 <mjansen> yea
    Jun 05 23:00:49 <hbelusca> mjansen: do we support these .local files?
    Jun 05 23:00:52 <mjansen> we dont
    Jun 05 23:00:54 <mjansen> windows does
    Jun 05 23:15:48 <x86corez> moment... I'll try with .local
    Jun 05 23:18:43 <x86corez> mjansen: I've created git.exe.local but it still doesn't load msvcrt.dll in this directory

    Но и этот вариант почему-то тоже не сработал. Возможно сказался тот факт, что все эксперименты я проводил на серверной версии Windows Server 2008 R2.


    Последнюю идею предложил Гермес:


    Jun 05 23:19:28 <hbelusca> last solution: patch "msvcrt" name within git and perhaps other mingwe dlls ^^
    Jun 05 23:20:12 <x86corez> good idea about patching!

    При помощи WinHex я заменил все вхождения подстроки msvcrt в файле git.exe на msvcrd, и переименовал msvcrt.dll от ReactOS соответствующим образом, и вот что получилось:


    image


    Jun 05 23:23:29 <x86corez> Yes! guilty is msvcrt :)
    Jun 05 23:25:37 <hbelusca> ah, so as soon as git uses our msvcrt we get the problem on windows.
    Jun 05 23:25:38 <x86corez> hbelusca, mjansen, https://image.prntscr.com/image/FoOWnrQ4SOGMD-66DLW16Q.png
    Jun 05 23:25:58 <hbelusca> aha and it asserts <3
    Jun 05 23:26:03 <hbelusca> (it shows the assertion now)

    Теперь уже в Windows мы получили то же самое сообщение об ошибке! А это означает, что источник проблемы в реализации одной из функций msvcrt из ReactOS.


    Можно также отметить, что под Windows текст исключения отображается корректно.


    Jun 05 23:26:13 <x86corez> but it prints text and correctly.
    Jun 05 23:26:20 <hbelusca> oh
    Jun 05 23:26:33 <x86corez> and on ROS it doesn't print in most cases xD
    Jun 05 23:26:38 <hbelusca> so also it excludes another hypothesis, namely that it could have been a bug in our msvcrt/crt
    Jun 05 23:26:56 <hbelusca> So possibly a strange bug in our console

    Оставалось лишь выяснить, какая функция в msvcrt предоставляет полный путь к исполняемому файлу запущенного приложения. Немного погуглив, я предположил, что дело в функции _pgmptr.


    Jun 06 00:07:43 <x86corez> https://msdn.microsoft.com/en-us/library/tza1y5f7.aspx
    Jun 06 00:07:57 <x86corez> When a program is run from the command interpreter (Cmd.exe), _pgmptr is automatically initialized to the full path of the executable file.
    Jun 06 00:08:01 <x86corez> this ^^)
    Jun 06 00:08:50 <hbelusca> That's what GetModuleFileName does.
    Jun 06 00:09:04 <x86corez> yeah
    Jun 06 00:10:30 <hbelusca> Of course in ROS msvcrt we don't do this, but instead we initialize pgmptr to what argv[0] could be.
    Jun 06 00:11:08 <hbelusca> That's one thing.
    Jun 06 00:11:34 <hbelusca> The other thing is that nowhere it appears (in MS CRT from VS, or in wine) that argv is initialized using pgmptr.
    Jun 06 00:13:33 <x86corez> hbelusca, I've checked argv[0] in some ROS command line tools, running them in Windows
    Jun 06 00:13:56 <x86corez> they all interpret argv[0] as command line, not full path
    Jun 06 00:14:04 <x86corez> so... I think it's git specific behaviour
    Jun 06 00:14:16 <x86corez> or specific mingw compiler settings
    Jun 06 00:28:12 <hbelusca> x86corez: I'm making a patch for our msvcrt, would be nice if you could test it :)
    Jun 06 00:28:21 <x86corez> I'll test it

    Гермес прислал ссылку на патч, я вручную применил его и пересобрал систему, после чего всё магическим образом заработало как надо!


    image


    Jun 06 00:34:26 <x86corez> hbelusca, IT WORKS!
    Jun 06 00:35:10 <hbelusca> L O L
    Jun 06 00:35:18 <hbelusca> So it seems that something uses pgmptr to rebuild an argv.
    Jun 06 00:35:52 <x86corez> I've even able to clone :)
    Jun 06 00:36:19 <hbelusca> \o/
    Jun 06 00:36:21 <gigaherz> 2.10.0-rc2? not the release?
    Jun 06 00:36:24 <hbelusca> ok I'm gonna commit that stuff.
    Jun 06 00:36:43 <hbelusca> x86corez: gonna have ROS self-hosting <33
    Jun 06 00:36:48 <x86corez> yeah!
    Jun 06 00:37:01 <x86corez> gigaherz: I've built that from sources
    Jun 06 00:37:37 <gigaherz> oh, for testing this bug? o_O
    Jun 06 00:37:50 <sanchaez> yes, you missed the fun :p
    Jun 06 00:39:46 <x86corez> git 2.10.0-windows.1 (release) works too!
    Jun 06 00:39:54 <encoded> commit!!!

    Послесловие


    Таким образом, ещё один баг, косвенно препятствующий само-сборке ReactOS внутри ReactOS, был исправлен благодаря коллективным усилиям. Забавным совпадением является тот факт, что незадолго до этого был исправлен другой баг в том же msvcrt (а именно в функции qsort), который не позволял собрать драйверы USB в ReactOS.


    Я участвую в разработке многих проектов, написанных на разных языках программирования, как закрытых, так и с открытым исходным кодом. С проектом ReactOS я сотрудничаю с 2014 года, но активно помогать и писать код начал только в 2017. Работать в этой области особенно интересно, потому что это целая операционная система! Чувствуется огромный масштаб результата, в который были вложены усилия, а также приятное ощущение, что одним багом стало меньше! :)


    Кто-то наверняка задастся вопросом, почему я помогаю именно ReactOS, а не Linux например. Так исторически сложилось, что в большинстве случаев я пишу программы для Windows, а мой любимый язык программирования — Delphi. Возможно именно поэтому архитектура Windows NT вместе с Win32 API мне очень интересна, а проект свободной операционной системы ReactOS воплощает в реальность давнюю мечту — на практике позволяет узнать, как всё это устроено изнутри.


    Надеюсь, вам было интересно прочитать мою первую статью здесь. С нетерпением жду ваших комментариев!


    Ссылки


    Фонд ReactOS 200,22
    Операционная система
    Поделиться публикацией
    Похожие публикации
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 38
      –12
      Delphi, ReactOS, IRC… закопайте стюардессу, ну хотя бы одну.
      Я шучу.., но в каждой шутке есть доля правды.
        +9
        Несмотря на все потуги хипстеров эти проекты продолжают жить и приносить пользу людям
          +2
          Когда Delphi и IRC шли в строю, тогда те кто ничего не хотел изучать использовали дос и ассемблер называя остальных аналогом слова хипстер. (У меня такой знакомый «программист» ушел в 40 лет из программистов в эникейщики.) Я сам тоже консерватор и Delphi держался долго, но ничто не вечно под луной.
            –1
            Насчёт IRC — ему пока что нет ни одного аналога с таким же количеством разных клиентов и серверов. И да, он до сих пор используется большей частью разработчиков
              0
              Все мы прекрасно понимаем почему им могут пользоваться, и почему он безнадежно устарел. Но не количество клиентов важный критерий. (Потому кстати и клиентов много что он очень простой как ftp, но вот последний недавно «забанили» в firefox и chrome.)
                0
                FF и Chrome рано или поздно забанят и http без сертификатов.
                  0
                  Сомневаюсь, как они сами говорили, это избавление от не нужного кодового груза.
                  И это совсем не похоже на заботу о безопасности пользователей. FTP ничем не хуже HTTP на страницах с HTTPS. Кроме того есть FTPS, но никого не волнует. С учетом этого не факт что http запретят, просто будут ставить красный замочек рядом и все (что правильно по крайней мере для сайтов с полями ввода). К тому же как на счет локалхостов? Множество программ имеют веб интерфейсы, поднятые на коленке dev версии сайтов, а просто сохраненные страницы? Не, можно поднять https на localhost, но это мало кому нужное приключение.
                    +3
                    Т.е. из кодовой базы в миллионы строк они решили выпилить небольшой кусочек (и при том — функциональный), типа чистку произвели? Ну ок.
                      +2

                      FTP не забанили (ещё), а запретили вставку элементов находящихся на ftp:// в страницы.
                      Т.е. открывать ftp-серверы в Firefox по прежнему можно, клиент никуда не делся.


                      https://bugzilla.mozilla.org/show_bug.cgi?id=1404744

                        0
                        Ну я написал в кавычках, но обещают совсем убрать поддержку. Более того не запретили вставку элементов, а добавили опцию в настройках запрещающую вставку ftp элементов, по умолчанию выключенную.
                  +1
                  Время IRC уже давно прошло и популярность его падает, сейчас в сети IRC 390тысяч пользователей вообще по всему миру, много это или мало? в начале 2000х только в десятке крупнейших сетей было больше 200тыр пользователей (в каждой из)

                  и про «большую часть» — это очень интересная статистика
                  0
                  Вообще-то Delphi живее всех живых. В последней Rad Studio можно написать приложение за пол часа, не написав при это ни одной строчки кода, используя LiveBindings, и откомпелировать для Andriod, iOS, OSx, Windows и Linux
                    +2
                    Я это слышу еще со времен VB4 (а то мож и раньше, но я с VB4 столкнулся с первым и там были такие слова что «скоро код будет писать не нужно!!»), а тут вы предлагаете как аргумент в 2018 году то что в 1995 году считалось «вау» функцией… только вот код всеравно все пишут
                      –2
                      Сколько пробовал этот RAD — ничего глючней не видел.
                    –1
                    C одной стороны, вы правы. И для своего времени это были прекраксные иснтрументы. Но сейчас есть лучшие, и более динамично развивающиеся. И только по инерции матёрые (читай: старой школы) айтишники продолжают пользоваться старьём, только продлевая его агонию и плодя зоопарк технологий. Я бы здесь ещё поставил первым пунктом списка на закапывание исчадие ада под названием mailing lists (простите, наболело).
                      0
                      В некоторых случаях — таки к сожалению. Мы работаем со всяким нестандартным оборудованием типа сенсоров веса, дальнобойных RFID-ридеров и т.п. Конфигураторы для этого добра китайцы почему-то пишут на Дельфи (или нам просто везет в последнее время). Если код на .NET обычно реверсится за час-два и к концу дня уже рожается нормальный command-line конфигуратор — то с Дельфи приходится вспоминать Ассемблер на котором я не писал лет 25.
                        0
                        Ну это проблема не Delphi, а любого компилируемого языка, хоть Delphi, хоть C++, Rust, C и т.д.
                        Напротив — хорошо что Delphi, много информации о типах содержится в rtti, формы доступны в исходниках, названия функций и т.д.
                          0
                          {$RTTI EXPLICIT METHODS([vcPublished]) PROPERTIES([vcPublished]) FIELDS([vcPublished])}

                          И всё, данных RTTI в бинарнике больше нет. :)

                            0
                            Безусловно можно и вырезать, но во первых все не вырезает, во вторых мало кто заморачивается с этим. Особенно учитывая то, что многие прикручивают отправку сообщения об ошибках и падениях, с развернутым стеком, и т.д. где информация о типах полезна.
                    0
                    Круто!
                      +2
                      А где код с ошибкой? Или хотя бы ссылка на коммит? Финал драмы испорчен)
                        0
                        Ссылка на коммит есть в списке ссылок в самом низу ;)

                        Если вы про прежнюю ошибку в qsort, то я отвечал вот тут: habr.com/company/reactos/blog/413461/#comment_18746791
                          0
                          Я просил ссылку на коммит с исправлением этого бага) Всего пара десятков строк — и бага нет)
                          За qsort — спасибо.
                      +3
                      Хорошо описано, читается как детектив
                        0
                        Чтобы статья стала полноценным детективом, надо было написать ещё про Ватсона :D
                        +1
                        Всегда интересно такое почитать.
                          +2
                          Скоро будет еще отчет от разработчика загрузичка системы с поддержкой BTRFS
                          +1

                          Весьма познавательно, спасибо! А это в мемориз: "недокументированные подводные камни" )))

                            0

                            Тоже мой любимый ЯП делфятина. Но если цепляться за него, можно остаться без работы). Приходится жабить на жабе в мире кровавого интерпрайза)) хотя на делфи с удовольствием беру править г@вно проекты на фрилансе, особо денег не приносит, типа хобби) спасибо за статью.

                              0
                              Так что там за глюк-то был с выводом текста ошибки? Или было решено победить его индусским методом (раз баг случается в таком-то случае — значит, меняем условия так, чтобы этот случай в этом месте не возникал)? :)
                                +1
                                С этим глюком пока никто не разбирался, по-моему ещё даже тикет в JIRA не открыли… Поскольку проблема с git разрешилась, на эту второстепенную проблему похоже забили.

                                Там при возникновении исключения выводы из stdout и stderr как-то по-хитрому смешиваются между собой, и одновременно выводятся в консоль.

                                Впрочем, я ведь могу собрать git, добавив assert(false); например… так и сделаю!
                                  0
                                  Похоже на то, что строка «assertion failed ...» является двухбайтовой (типа wchar_t), и пробелы соответствуют нулевым байтам каждого двухбайтового символа
                                    0

                                    Возможно где-то есть недостающая (или лишняя) перекодировка в UCS-2.

                                  0

                                  По-французски Hermes это разве не Эрме? Так же как Эркюль Пуаро совсем не Геркулес.

                                    0
                                    Честно говоря, не знаю как правильно, т.к. из не родных языков знаю только английский. В русскоязычной части сообщества ReactOS Гермеса всегда называли именно так. :)
                                      0
                                      А он это слышал?)
                                        0
                                        Он по-русски ни с кем не разговаривает. Поэтому — нет )
                                      +1

                                      Сегодня он лично ответил в IRC:


                                      the final 's' is pronunced. so "Гермес" is the best translitteration, I think.

                                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                    Самое читаемое