ReactOS — это проект, где победу над регрессией, появление новой фичи или её рабочего прототипа празднуют так громко, что FOSS-сообществу приходится отвлекаться от переписывания всего на Rust и полемик о systemd. В последний раз мы проверяли ReactOS в 2013 году, почти одиннадцать лет назад. Проверка была неточной ввиду неполного понимания структуры папок, из-за чего в поле видимости PVS-Studio оставались компоненты Wine. Пришло время освежить память и провести новую проверку, учитывая опыт предыдущей недоработки.
Введение
Напомним, что ReactOS «под капотом» использует не ядро GNU/Linux, а самостоятельно написанное ядро, воспроизводящее поведение Windows Server 2003 R2 в 32-битной редакции и Windows Vista в 64-битной. Использование компонентов Wine, прослойки совместимости Windows API для POSIX‑совместимых операционных систем, для реализации пользовательской среды Windows и возможности запуска приложений для Windows совершенно не означает, что операционная система будет использовать ядро GNU/Linux. При установке WineVDM на Windows 11 ядро вашей копии системы не заменится на ядро условного Debian 12, верно? :)
Не менее важно отметить, что воспроизведение поведения ядра целевой версии Windows осуществляется исключительно через тесты функций и дизассемблирование: использование утёкших исходников Windows запрещено.
Legal notice: If you have seen proprietary Microsoft Windows source code (including but not limited to the leaked Windows NT 3.5, NT 4, 2000 source code and the Windows Research Kernel), your contribution won't be accepted because of potential copyright violation.
Обратная разработка методом «чёрного ящика» для такого проекта — процесс трудоёмкий, и без ошибок её произвести невозможно. Эксперты в комментариях различных FOSS‑сообществ и новостных агрегаторов возмущённо реагируют на осознанный отказ разработчиков ReactOS от вкушения запретного плода, намекая на то, что операционная система находится 26 лет в альфа‑тесте, и «пора бы уже что‑то начать делать». Об этом в другой раз, а сейчас приступим к настройке PVS‑Studio для проверки кода.
Установка PVS-Studio
Загрузить PVS‑Studio можно перейдя на эту страницу. Чтобы произвести анализ проекта, понадобится лицензия, триальную версию которой можно получить здесь. Процедура установки PVS‑Studio не вызовет сложностей: каждый шаг сопровождается легко воспринимаемым пояснением, а при возникновении трудностей всегда поможет справка по быстрому запуску под Windows. Потребуется два компонента: мониторинг компиляторов (C and C++ Compiler Monitoring) и любая интеграция с IDE. Мы будем использовать расширение для Visual Studio 2022. Актуальная на момент написания статьи версия анализатора — 7.30.
Конфигурация сборки и запуск её анализа
ReactOS — это ещё один пример проекта с нестандартной процедурой анализа, наряду с проектами Unreal Engine. ReactOS Build Environment (RosBE) является полноценным набором инструментов для создания установочного или Live‑носителя операционной системы и содержит специальные версии утилит CMake, Bison, Flex и Ninja. Анализу будет подвергнута стандартная отладочная сборка, выполненная через GCC с кодом, актуальным на момент коммита 00c4b3d ветки master. Произведём настройку рабочего окружения и рассмотрим сам процесс.
Анализ проекта будет осуществляться через CLMonitor. Что он собой представляет? Это консольная утилита в составе PVS‑Studio, которая позволяет производить анализ проектов независимо от их системы сборки. Главное условие — компилятор должен быть в перечне поддерживаемых. Поскольку за компиляцию отвечает GCC, то каждый вызов компилятора будет обнаружен и записан в журнал.
Запускаем RosBE, переходим в папку с исходными текстами из извлечённого репозитория и выполняем сценарий configure.cmd. По окончании конфигурации запускаем CLMonitor (указан путь по умолчанию) в режиме мониторинга:
"C:\Program Files (x86)\PVS-Studio\CLMonitor" monitor
Запускаем сборку любой цели, например, bootcd (только установочный носитель):
cd output-MinGW-i386
ninja bootcd
После завершения сборки закрываем CLMonitor c сохранением результатов:
"C:\Program Files (x86)\PVS-Studio\CLMonitor" analyze -l output.plog
Теперь можно приступить к анализу. Запускаем Visual Studio, в окне приветствия выбираем вариант Continue without code. Далее открываем сохранённый CLMonitor файл журнала. Мы его сохранили в ту же папку, где находятся выходные файлы RosBE.
Чтобы открыть сохранённый файл журнала, выберите пункт Extensions → PVS‑Studio → Open/Save → Open Analysis Report.
Анализ найденных ошибок
«В первую очередь — самое важное» — такой фразой приветствует Microsoft Office 2016 при первом запуске, предлагая произвести начальную настройку. Не менее важен первый запуск PVS‑Studio в любом проекте, где его ни разу не использовали, так как нам необходимо по максимуму убрать из перечня проверяемых файлов сторонние компоненты: вспомогательные утилиты для генерации ISO‑образа, общую папку RosBE и файлы Public SDK. Они пересекаются определениями с заголовками Windows SDK, в результате чего возникает огромное количество предупреждений о переопределении базовых типов или несовпадении аннотаций. Производится эта операция в настройках плагина PVS‑Studio в разделе Don't Check Files.
Для вашего удобства: список исключённых папок из кодовой базы ReactOS в форме текста и относительных путей. Путь до папки share из RosBE потребуется указать в абсолютном формате.
dll\directx\wine\
dll\win32\advapi32\wine\
dll\win32\dbghelp\
drivers\filesystems\btrfs\
drivers\filesystems\udfs\
sdk\include\psdk\
sdk\lib\3rdparty\
sdk\tools\
Теперь самое время поискать защитные очки, ведь ReactOS известна своим умением «взорваться» от косого взгляда, над чем иногда шутят и сами разработчики :)
По случаю приближающейся 11-й годовщины с момента последней проверки ReactOS, представляю вашему вниманию 11 интересных находок в кодовой базе проекта (среди них — один сюрприз)! Будем постепенно разгоняться, начиная с классических копипаст и заканчивая по‑настоящему «разрушительными сбоями».
Да, Windows делает так же, но точно ли так же?
V501 There are identical sub-expressions 'DCDest->dctype == DCTYPE_INFO' to the left and to the right of the '||' operator. bitblt.c 64
BOOL APIENTRY
NtGdiAlphaBlend(
HDC hDCDest,
LONG XOriginDest,
LONG YOriginDest,
LONG WidthDest,
LONG HeightDest,
HDC hDCSrc,
LONG XOriginSrc,
LONG YOriginSrc,
LONG WidthSrc,
LONG HeightSrc,
BLENDFUNCTION BlendFunc,
HANDLE hcmXform)
{
PDC DCDest;
PDC DCSrc;
....
if (DCDest->dctype == DCTYPE_INFO || DCDest->dctype == DCTYPE_INFO) // <=
{
GDIOBJ_vUnlockObject(&DCSrc->BaseObject);
GDIOBJ_vUnlockObject(&DCDest->BaseObject);
/* Yes, Windows really returns TRUE in this case */
return TRUE;
}
....
}
Поверим, что Windows действительно возвращает TRUE при совпадении типов исходного и конечного контекстов устройств GDI, но DCSrc почему-то в сравнении не участвует, из-за чего смешивание поверхностей не происходит! Об этом и сообщает диагностика: в условии стоят два одинаковых подвыражения, разделённые оператором ИЛИ.
Ваш сертификат безопасности, пожалуйста.
V564 The '&' operator is applied to bool type value. You've probably forgotten to include parentheses or intended to use the '&&' operator. loaddlg.cpp 376
#define SECURITY_FLAG_SECURE 0x00000001
static BOOL
CertGetSubjectAndIssuer(HINTERNET hFile,
CLocalPtr<char> &subjectInfo,
CLocalPtr<char> &issuerInfo)
{
....
DWORD size, flags;
size = sizeof(flags);
if (!InternetQueryOptionA(hFile,
INTERNET_OPTION_SECURITY_FLAGS,
&flags,
&size))
{
return FALSE;
}
if (!flags & SECURITY_FLAG_SECURE) // <=
{
return FALSE;
}
....
}
Потерялись скобки: условие выполнится только в том случае, если переменная flags равна 0. Во всех остальных случаях оператор отрицания '!' вернёт значение false. Побитовая операция И в этом случае уже не играет никакой роли: условие всегда ложно и все соединения рассматриваются как защищённые.
Frown The Pointers
Продолжая тему проверки подлинности, под руку попал системный FTP-клиент. Авторизация на сервере и переключение прокси не оставили меня равнодушным к особо жестокому обращению с памятью в строках. Куда будет поставлен терминальный ноль? Где закончится строка? Чьи данные будут повреждены? Пришло время вызвать Access Violation!
V692 An inappropriate attempt to append a null character to a string. To determine the length of a string by 'strlen' function correctly, a string ending with a null terminator should be used in the first place. ftp.c 1355
#define MAXHOSTNAMELEN 64
char* hostname;
void pswitch(int flag)
{
....
static struct comvars {
int connect;
char name[MAXHOSTNAMELEN];
....
} proxstruct, tmpstruct;
struct comvars *ip, *op;
....
if (flag) {
if (proxy)
return;
ip = &tmpstruct;
op = &proxstruct;
proxy++;
}
....
if (hostname) {
(void) strncpy(ip->name, hostname, sizeof(ip->name) - 1);
ip->name[strlen(ip->name)] = '\0';
} else
ip->name[0] = 0;
....
}
Нас интересует следующая строка:
ip->name[strlen(ip->name)] = '\0';
В ней программист хочет записать терминальный ноль ('\0') в конец строки. Юмор ситуации в том, что для определения позиции для записи '\0' используется функция strlen. Функция определяет конец строки, осуществляя поиск ближайшего терминального нуля. Получается, чтобы записать конец строки, надо вначале найти конец строки :)
Терминальный ноль будет записан в то место, где он и так уже находится. Возникает опасная ситуация, так как это может произойти за пределами буфера. Формально это приводит к неопределённому поведению, а на практике может вызвать Access Violation.
В разбираемом случае ситуация не такая страшная. Обратите внимание, что объект tmpstruct является статическим. Это значит, что все его поля будут empty-инициализированы. В том числе и буфер name, который будет заполнен нулями.
В буфер копируется строка, с учётом необходимости добавить терминальный ноль. Поэтому, даже если строка-источник очень длинная и функция strncpy не запишет в конце '\0', он там уже будет.
Вернёмся к строке:
ip->name[strlen(ip->name)] = '\0';
Выхода за границу массива здесь нет, но сама операция бессмысленна. '\0' записывается туда, где он и так уже находится. Строчку можно смело удалить.
Надеюсь, у меня получилось объяснить эту интересную аномалию кода.
V1010 Unchecked tainted data is used in index: 'strlen(tmp)'. ftp.c 216
int login(const char *host)
{
char tmp[80];
....
while (user == NULL) {
const char *myname = "none"; // This needs to become the username env
if (myname)
printf("Name (%s:%s): ", host, myname);
else
printf("Name (%s): ", host);
(void) fflush(stdout);
(void) fgets(tmp, sizeof(tmp) - 1, stdin);
tmp[strlen(tmp) - 1] = '\0'; // <=
if (*tmp == '\0')
user = myname;
else
user = tmp;
}
....
}
Ещё более страшная вариация ошибки, найденной диагностикой V692. Про то, как можно испортить себе вечер функцией fgets, мы ранее рассказывали в статье «Стреляем в ногу, обрабатывая входные данные». Рекомендую ознакомиться, если интересно узнать, где кроется подвох.
Никто ничего не видел!
После увиденного в клиенте FTP срочно требовалось что-то для успокоения. Местная реализация модуля Windows Installer радует совершенно бесполезной операцией уточнения длины буфера lpValue (функция использует переменную pcchValue для обозначения длины запрошенного значения):
V519 The '* pcchValue' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1779, 1782. msi.c 1782
UINT WINAPI MsiGetPatchInfoExW(LPCWSTR szPatchCode, LPCWSTR szProductCode,
LPCWSTR szUserSid, MSIINSTALLCONTEXT dwContext,
LPCWSTR szProperty, LPWSTR lpValue,
DWORD *pcchValue)
{
....
if ((*val && *pcchValue < len + 1) || !lpValue)
{
if (lpValue)
r = ERROR_MORE_DATA;
*pcchValue = len * sizeof(WCHAR);
}
*pcchValue = len;
....
}
V519 The 'Status' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1254, 1255. cabinet.c 1255
ULONG
CabinetExtractFile(IN PCABINET_CONTEXT CabinetContext,
IN PCAB_SEARCH Search)
{
....
if (Status != CS_SUCCESS)
{
DPRINT("Cannot uncompress block\n");
if (Status == CS_NOMEMORY)
Status = CAB_STATUS_NOMEMORY;
Status = CAB_STATUS_INVALID_CAB;
goto UnmapDestFile;
}
....
}
Где установщик Windows Installer, там и CAB‑архивы, так как в последние, как правило, упаковываются файлы для экономии места. Вероятно, автор хотел вернуть CAB_STATUS_NOMEMORY, но не обратил внимание, что статус не доходит до возврата функцией, поскольку сразу заменяется на «некорректный CAB‑файл», что приведёт к неправильной обработке ошибки приложением.
Ваш минус ничего не значит
V605 Consider verifying the expression. An unsigned value is compared to the number -3. link.c 267
typedef enum {
HLINKSETF_TARGET = 0x00000001,
HLINKSETF_LOCATION = 0x00000002
} HLINKSETF;
typedef unsigned long DWORD;
static HRESULT WINAPI IHlink_fnSetStringReference(
IHlink* iface,
DWORD grfHLSETF,
LPCWSTR pwzTarget,
LPCWSTR pwzLocation)
{
HlinkImpl *This = impl_from_IHlink(iface);
TRACE("(%p)->(%i %s %s)\n", This, grfHLSETF, debugstr_w(pwzTarget),
debugstr_w(pwzLocation));
if(grfHLSETF > (HLINKSETF_TARGET | HLINKSETF_LOCATION) &&
grfHLSETF < -(HLINKSETF_TARGET | HLINKSETF_LOCATION)) // <=
return grfHLSETF;
....
}
Теперь пора спуститься ещё глубже в пользовательской области. COM, ActiveX — не бросает ли вас в дрожь при упоминании этих сущностей? Здесь происходит что-то очень странное с обработкой гиперссылок при установке их целей. Вторая половина проверки вызывает неудобные вопросы.
Звук неуверенности
V560 A part of conditional expression is always true: adsi->pwfxSrc->wBitsPerSample == 16. imaadp32.c 794
V560 A part of conditional expression is always true: adsi->pwfxSrc->wBitsPerSample == 16. imaadp32.c 796
static LRESULT ADPCM_StreamOpen(PACMDRVSTREAMINSTANCE adsi)
{
....
if (adsi->pwfxSrc->nSamplesPerSec != adsi->pwfxDst->nSamplesPerSec ||
adsi->pwfxSrc->nChannels != adsi->pwfxDst->nChannels ||
adsi->pwfxSrc->wBitsPerSample != 16) // <=
goto theEnd;
nspb = ((LPIMAADPCMWAVEFORMAT)adsi->pwfxDst)->wSamplesPerBlock;
TRACE("spb=%u\n", nspb);
/* we check that in a block, after the header, samples are present on
* 4-sample packet pattern
* we also check that the block alignment is bigger than
* the expected size
*/
if (((nspb - 1) & 3) != 0) goto theEnd;
if ((((nspb - 1) / 2) + 4) * adsi->pwfxDst->nChannels
< adsi->pwfxDst->nBlockAlign
) goto theEnd;
/* adpcm coding... */
if (adsi->pwfxSrc->wBitsPerSample == 16 // <=
&& adsi->pwfxSrc->nChannels == 2)
aad->convert = cvtSS16imaK;
if (adsi->pwfxSrc->wBitsPerSample == 16 // <=
&& adsi->pwfxSrc->nChannels == 1)
aad->convert = cvtMM16imaK;
....
}
Звуковая подсистема ReactOS тоже больное место. Передискретизации (resampling) нет, громкость каналов не синхронизирована... Но представленный образец кода со звуковой подсистемой связан косвенно: это кодек ADPCM.
Суть ошибки: уже ранее была выполнена проверка разрядности сэмплов. Если разрядность сэмплов отличается от 16 бит, то происходит переход к метке theEnd. Последующие проверки разрядности всегда будут истинны.
Взаимоисключающие параграфы
V637 Two opposite conditions were encountered. The second condition is always false. Check lines: 2389, 2392. devinst.c 2389
HDEVINFO WINAPI SetupDiGetClassDevsExW(
CONST GUID *class,
PCWSTR enumstr,
HWND parent,
DWORD flags,
HDEVINFO deviceset,
PCWSTR machine,
PVOID reserved)
{
if (flags & DIGCF_ALLCLASSES)
{
/* The caller wants all classes. Check if
* the deviceset limits us to one class */
....
}
else if (class)
{
/* The caller wants one class. Check if it matches deviceset class */
....
}
else if (!IsEqualIID(&list->ClassGuid, &GUID_NULL)) // <=
{
/* No class specified. Try to use the one of the deviceset */
if (IsEqualIID(&list->ClassGuid, &GUID_NULL)) // <=
pClassGuid = &list->ClassGuid;
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
goto cleanup;
}
....
}
Код в любом случае вернёт ошибку «Параметр задан неверно», так как GUID установленного устройства не был определён, и его свойства получить нельзя. Пока мы не отошли от работы с установленными устройствами, взглянем на ненавидимый разработчиками драйвер UniATA. Да, это сторонний компонент, его надо было из проверки исключить наряду с другими сторонними драйверами, но удержаться и пройти мимо логической путаницы и примера того, как не надо оформлять код... Нет, такое нельзя упускать.
В DMA позвонили и сбросили
V646 Consider inspecting the application's logic. It's possible that 'else' keyword is missing. id_ata.cpp 7820
ULONG
NTAPI
AtapiSendCommand(IN PVOID HwDeviceExtension, IN PSCSI_REQUEST_BLOCK Srb,
IN ULONG CmdAction)
{
....
if((Srb->Cdb[0] == SCSIOP_REQUEST_SENSE)
&& !(deviceExtension->HwFlags & UNIATA_SATA)) {
KdPrint2((
PRINT_PREFIX "AtapiSendCommand: SCSIOP_REQUEST_SENSE -> no dma setup (2)\n"
));
....
AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
} if(AtaReq->TransferLength) { // <=
if(!dma_reinited) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit()\n"));
AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
....
}
} else {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: zero transfer\n"));
....
if(!deviceExtension->opt_AtapiDmaZeroTransfer
&& !(deviceExtension->HwFlags & UNIATA_SATA)) {
KdPrint2((PRINT_PREFIX "AtapiSendCommand: AtapiDmaReinit() to PIO\n"));
AtapiDmaReinit(deviceExtension, LunExt, AtaReq);
}
}
....
}
Исходя из того, что в условиях проводятся разные проверки, здесь либо не хватает переноса строки, либо повторная инициализация DMA должна происходить в случае, если первая проверка вернула FALSE (предлагаемый диагностикой вариант), или если ситуация вынуждает перейти в PIO (программный ввод/вывод). Слишком подозрительно, слишком резкий "запах" от кода исходит. Был ли этот запах предвестником большой беды? Неопределённо.
Кастовать нельзя продвинуть
V610 Undefined behavior. Check the shift operator '<<'. The left operand '(~(UCHAR) 0x0d)' is negative. id_ata.cpp 2705
BOOLEAN
NTAPI
AtapiResetController(IN PVOID HwDeviceExtension, IN ULONG PathId,
IN BOOLEAN CompleteType)
{
....
case ATA_NVIDIA_ID: {
ULONG offs;
ULONG Channel = deviceExtension->Channel + j;
....
if(ChipFlags & NVQ) {
KdPrint2((PRINT_PREFIX " NVQ, 32bits reg\n"));
AtapiWritePortEx4(NULL,
(ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), offs + 4,
AtapiReadPortEx4(NULL,
(ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), offs + 4)
& ((~(ULONG)0x0000000d) << (!Channel * 16))
);
} else {
AtapiWritePortEx1(NULL,
(ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), offs + 1,
AtapiReadPortEx1(NULL,
(ULONGIO_PTR)(&deviceExtension->BaseIoAddressSATA_0), offs + 1)
& ((~(UCHAR)0x0d) << (!Channel * 4)) // <=
);
}
....
}
}
До стандарта C++20 сдвиг отрицательного числа считался неопределённым поведением. Проблема в том, что код драйвера UniATA на деле является кодом на C, компилируемым как код C++, и явно без применения спецификаций C++20, поэтому это гарантированно неопределённое поведение. Можно поиграть в экстрасенса и попытаться угадать, что ожидал получить автор драйвера: намеренное воспроизведение неопределённого поведения или же каст инвертированного 0×0D до UCHAR, который выглядел бы как (UCHAR)~0×0D? Ничего не понятно, но очень интересно. Нужно найти материнскую плату с SATA‑контроллером NVIDIA и посидеть с отладчиком...
То самое, одиннадцатое мгновение ReactOS
Тем не менее есть лучик света в тёмном царстве: в кодовой базе ReactOS присутствует один компонент, в котором PVS‑Studio не выявил проблем. Он находится в зоне высокой ответственности — в загрузчике. Благодаря Джастину Миллеру (DarkFire01) в ReactOS появилась поддержка загрузки через UEFI, и именно этот компонент FreeLoader чист с точки зрения анализатора. Это определённо заслуживает награды: два года назад это было экспериментом, через год пошли попытки запуска на других устройствах, и сейчас это в основной кодовой базе. И мы это ставим 11-м мгновением ReactOS.
На подходе поддержка многопроцессорности, над которой бились куда дольше, чем над UEFI. Очень надеемся, что многопроцессорность будет так же изящно реализована, как и обновлённый загрузчик, потому что параллельная обработка данных на уровне ядра не прощает ошибок :)
Заключение
Несмотря на нестандартную систему сборки, анализатор PVS‑Studio с лёгкостью смог выполнить поставленную задачу статического анализа всей кодовой базы операционной системы. ReactOS продвинулась в повышении качества кода, но проблем по‑прежнему много. Очень радует, что мейнтейнеры справляются с решением сложных задач и рвут шаблоны «экспертам» вопреки их нескончаемым волнам негатива, но расстраивает риск отклонения реализации недостающего функционала без объективной причины.
Отношение созданных задач (красные) к решённым (зелёные) за 180 дней в ReactOS Jira, данные на 16.04.2024
Надеюсь, что юбилейный ре‑обзор ReactOS помог вам получить новые знания в области работы с низкоуровневым кодом или освежить память. Хотите попробовать проверить свой проект с помощью PVS‑Studio? Процесс несложный, а полезный результат не заставит себя ждать! А если ваш проект с открытым исходным кодом, то у вас есть возможность получить лицензию для OSS‑проектов.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Taras Shevchenko. Eleven moments of ReactOS: user mode gets better?.
Комментарии (17)
speshuric
14.05.2024 09:53+1Теперь пора спуститься ещё глубже в пользовательской области. COM, ActiveX — не бросает ли вас в дрожь при упоминании этих сущностей?
Да ладно, они же такие милые и уютные IUnknown и IDispatch, компилятор MIDL, OLE,
arteast
14.05.2024 09:53+1Половина ошибок на самом деле в Wine. Технически они, конечно, и в ReactOS есть по факту переиспользования кода, но подложили их туда вовсе не разработчики ReactOS :)
slonopotamus
14.05.2024 09:53+1подложили их туда вовсе не разработчики ReactOS
А кто же подложил код Wine в ReactOS?
Chalokian
14.05.2024 09:53Я удивлён, что это все не покрыто тестами. Я, конечно, не разработчик, а только балуюсь, но все подобные методы покрываю тестами. Или я не правильно понимаю, что и как тестировать? Я не троллю, мне правда интересно.
x86chk Автор
14.05.2024 09:53+2Покрытие тестами имеется, но не каждый угол покрыт ими. Можно посмотреть отработку автоматических регресс-тестов, в GitHub дополнительно каждый pull request прогоняется на «выживаемость» сборки. Есть хотя бы одна проваленная сборка не по причине технической неполадки (частая история с Visual Studio 2015) — PR не допускают к мерджу.
Кто-то даже фаззер натравливал на систему, от чего та громко взрывалась, не выдерживая потока неправильных данных. Скажем так, в ReactOS весь win32k просит капитального ремонта, но из-за очень интересной политики их релиз-менеджера, которому важнее почистить пробелы в ресурсных файлах, сэкономить 0.5 мс и два байта на компиляции отладочной сборки, чем заняться делом, все попытки побороть это проклятье юзерспейса заканчиваются утратой энтузиазма. Инициативная группа пытается (и у неё получается) проталкивать переход на целевую платформу NT 6.x, попутно выбрасывая цистерны костылей и велосипедов из системных библиотек, но, увы, процесс идёт медленно. Политика релиз-менеджера вызывает отторжение у новичков, из-за этого очень мало людей узнаёт про то, что с этой проблемой борются.
Caefah
14.05.2024 09:53Моё знакомство с ReactOS после моря розовых соплей в рекламе:
Лет 15 назад думаю, попробую — синий экран смерти на этапе установки.
Лет 10 назад. Ну уже все баги починили, попробую — синий экран смерти на этапе установки.
Лет 5 назад думаю, ну хоть на виртуалке гляну что за зверь да попробую — синий экран смерти сразу после процесса установки.
Сейчас думаю, что уже никогда не попробую. 15 лет обошёлся как-то и без этого говноподелия, и даже без Windows, значит и дальше обойдусь! :-Dtimoxa_dev
14.05.2024 09:53+4обошёлся как-то и без этого говноподелия, и даже без Windows
У вас просто нормальной операционной системы не было, сидите на своих юникса и плюетесь слюнями в нормальных людей
Caefah
14.05.2024 09:53Сарказм оценил. Улыбнуло :-)
В нормальных людей я не плевал, а поделился своим опытом "знакомства" с ReactOS.
Ещё вспомнил момент, как мне приятель делал презентацию. На ней ReactOS даже запустилась и показала Проводник, но ушла в BSOD в процессе установки MS Office.
x86chk Автор
14.05.2024 09:53+2но ушла в BSOD в процессе установки MS Office.
Раз за давностью лет описываются события, то на всякий случай внесу чуток радости — Office 2007 успешно устанавливается на ночных сборках 0.4.15. Есть глюки по интерфейсу, но несколько месяцев назад ситуация была куда хуже — слайды в PowerPoint рисовались вверх ногами вместе с внутренним интерфейсом, а Word рассыпался на части. Сейчас Word в лучшем случае рвётся при переключении отображения линейки и глючит шрифтами..
Hidden text
Caefah
14.05.2024 09:53Воистину воодушевляющее достижение! Куда уж "нашим" вышеупомянутым юниксам... :)
Ладно, ладно! Харэ минусовать! Сдаюсь! Я обеими руками за развитие опенсорсного софта! Весь мой ядовитый сарказм исходит от непонимания как за 15 лет (15, КАРЛ!) можно было умудриться не решить элементарных проблем со стабильностью работы ядра и защиты от сбоев на уровне userspace.Отныне обещаю отключить токсичность сейчас и даже в следующий раз, когда увижу очередные восторги с рекламой ErectOS и призывами попила бюджета для её развития. Чес-слово!
От меня плюс всем в карму! Спасибо, что читаете мои несуразности.
n0isy
14.05.2024 09:53Похоже они втолкнули туда UniATA, я с ним лет 20 назад возился в составе ReactOS))
x86chk Автор
14.05.2024 09:53+1Его оттуда уже выталкивать собираются, на его место нормальный драйвер ATAPI готовят.
datacompboy
Все же идея была сделать вот так:
и это стандартный паттерн использования в комбинации с strncpy
x86chk Автор
Вполне возможно, но мы уже никогда не узнаем, что же хотел сделать автор — blame показывает, что последний раз в FTP-клиент залезали 17 февраля 2006 года. Сделали и забыли.
Я бы всё же убрал эту операцию целиком.
datacompboy
Явное всегда лучше. По определению, если
strncpy
наступает на конец выданного буфера, она НЕ записывает туда ноль (я вежливый кролик, и промолчу про это поведение для str* функции). Да, можно полагаться на неявное обнуление структуры в данном конкретном случае в данном конкретном месте, но доп запись нуля никому хуже не сделает, а если там уже гарантирован ноль и компилятор может это доказать - вон он пусть и выкидывает эту строку (тем более, что для случая с sizeof он это сделать точно может).x86chk Автор
Спасибо за полезный комментарий! :)