commit -m "better"
2.96K subscribers
868 photos
105 videos
3 files
2.07K links
just random thoughts
Download Telegram
Как в Microsoft ловят data race в ядре(hint - c помощью профайлера бедного человека): https://www.usenix.org/legacy/events/osdi10/tech/full_papers/Erickson.pdf #debug

И, собственно, как сделать профайлер бедного человека своими руками: https://programmer.group/x86_-principle-and-example-of-single-step-debugging-for-64-platform.html
Жесть, самый странный #debug в моей жизни.

pg@:~/sources/mix strings ~/mix/realm/stable/bin/sway | grep hello
pg@:~/sources/mix ldd ~/mix/realm/stable/bin/sway
не является динамическим исполняемым файлом
pg@:~/sources/mix HELLO YES THIS IS DOGHELLOYES THIS IS DOG^C
pg@:~/sources/mix
pg@:~/sources/mix ldd ~/mix/realm/stable/bin/sway
не является динамическим исполняемым файлом
pg@:~/sources/mix strings ~/mix/realm/stable/bin/sway | grep HELLO
pg@:~/sources/mix strings ~/mix/realm/stable/bin/sway | grep DOG
HB_SCRIPT_DOGRA
G_UNICODE_SCRIPT_DOGRA
pg@:~/sources/mix 12345HELLOYES THIS IS DOG890
bash: 12345HELLOYES: команда не найдена
pg@:~/sources/mix 12345 HELLO YES THIS IS DOG 890

Я собрал sway, который вместо 6 и 7(пишу с другого хоста) печатает вот то, что вы видите сверху. Я, короче, в шоке. libinput:

5 event4   KEYBOARD_KEY            +1.513s  *** (-1) released
event4 KEYBOARD_KEY +1.967s *** (-1) pressed
HELLO event4 KEYBOARD_KEY +2.059s *** (-1) released
event4 KEYBOARD_KEY +2.345s *** (-1) pressed
YES THIS IS DOG event4 KEYBOARD_KEY +2.433s ***
(-1) released
event4 KEYBOARD_KEY +3.082s *** (-1) pressed
event4 KEYBOARD_KEY +3.330s *** (-1) pressed
^C

Вывод - приходит 1 нажатие, которое далее преобразуется в этот текст. Wayland передает клиентам keystrokes, значит, ошибка в коде клиента. Проверяем:

recvmsg(5, {msg_name=NULL, msg_namelen=0, msg_iov=
[{iov_base="\34\0\0\0\3\0\30\0n\n\0\0
\376\251d\5\10\0\0\0\1\0\0\0", iov_len=3128}, {iov_base=
"", iov_len=968}], msg_iovlen=2, msg_controllen=0,
msg_flags=MSG_CMSG_CLOEXEC}, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) = 24
write(7, "YES THIS IS DOG", 15) = 15
timerfd_settime(6, 0, {it_interval={tv_sec=0,
tv_nsec=40000000}, it_value={tv_sec=0, tv_nsec=600000000}},
NULL) = 0
epoll_pwait(3, [{events=EPOLLIN,
data={u32=2820241184, u64=5633522366240}}], 8, -1, [], 8) = 1
read(7, "YES THIS IS DOG", 24576) = 15
read(7, 0x7ffecfe04050, 24576) = -1 EAGAIN
(Ресурс временно недоступен)

[root@dynamic-vpn pg]# ls -la /proc/3101931/fd/7
lrwx------. 1 pg pg 64 дек 3 07:42 /proc/3101931/fd/7
-> /dev/ptmx

Единственная подозрительная библиотека, с которой слинкованы все клиенты:

/* Multiple keysyms. */
TEST_KEY(KEY_6, "HELLO", 0);
TEST_KEY(KEY_7, "YES THIS IS DOG", 0);

libxkbcommon-xkbcommon-1.3.1/test cat state.c | grep DOG
TEST_KEY(KEY_7, "YES THIS IS DOG", 0);
TEST_KEY(KEY_7, "YES THIS IS DOG", 0);

С%ка, я чуть не поседел... Один, печатаю в терминале, и тут на экране появляется "HELLO YES THIS IS DOG"...

Как оно пролезло из теста в реальный бинарь - в следующей серии.
В одном там рабочем чате с коллегами зашла речь, кто как смотрит порно. Мне пришлось признаться, что я для этого использую рабочий macbook, потому что в моем браузере все еще не работает поддержка видео. Собственно, у меня там 3 заметных проблемы:

1) Поддержка видео. Как починю, обязательно напишу про эту эпичную историю.
2) Про кривые иконки из-за старой librsvg я уже писал, надо или как-то затащить Rust, или научить это оффлоадить в inkscape. Я склоняюсь ко второму пути.
3) И сегодняшняя история - поддержка PDF!

Epiphany, как и многие, поддерживает PDF через PDF.JS. Но оно почему-то не работает. Конечно, как обычно, дело в динамическом связывании - код, которому нужен код читалки, не может его найти в runtime. И в данном случае дело не в статической линковке, а в чем-то еще(что-то с ресурсной системой glib, я не разобрался пока).

Чинить это займет время, а pdf-ки читать надо уже сейчас.

Я решил вечерочком собрать себе читалку - Evince. Думал, плевое дело, простая программа, все зависимости уже в репе, 5 минут, не больше. Ага, конечно.

* В программе есть плагины. Читатели у меня уже прошаренные, поэтому я просто скажу, что загрузка плагинов там по второму типу #plugins Плагины много времени не заняли, все же, это основная фишка дистрибутива.

* После загрузки программы я увидел надпись "unsupported mime type application/octet-stream", и тут я понял, что это надолго.

Не буду утомлять скучными подробностями #debug, но:

* glib неявно зависит от базы данных для определения mime types. Неявно - значит, все делает вид, что работает, до поры до времени, примерно как TLS в той же #glib.

* Пути для поиска этих данных вычисляются довольно нетривиальным образом.

* Самое страшное - сборка этих данных зависит от docbook xml, а это моя дикая боль. Я напишу об этом отдельно, но надо понимать, что там очень сложная динамическая линковка данных поверх XML, все это сдобрено perl, с легким налетом GNU. Я это затащить могу, но очень не хочу, и пока просто обходил стороной. А тут жесткая зависимость сборки.

Короче, я решил, что вместо всей этой херни я вкорячу старую-добрую libmagic, из пакета file https://www.darwinsys.com/file/. Хороший, древний, проверенный код, без изъебов.

revision 1.1
date: 1987/08/23 19:51:05; author: ian; state: Exp;
Initial revision


Код чуть младше меня.

Замечания по ходу процесса:

* Пришлось сделать thread-safe обертку над api libmagic: https://github.com/pg83/mix/blob/main/pkgs/lib/mimetype/mix.sh

* Как оно используется: https://github.com/pg83/mix/blob/main/pkgs/lib/glib/01.diff (блин, а код без аллокаций на C писать вполне норм!) Я бы хотел тут остановиться, и сказать, что оно заработало like a charm, но нет

* glib сначала пытается определить тип по расширению, в #libmagic этого нет. Я это обошел тем, что всегда определяю по данным. NVMe все стерпит.

* Без нужных ему данных glib определяет длину буфера для autodetect в 0. Ну, починил.

* Названия mime types в библиотеках немного расходятся. К счастью, авторы Evince это предусмотрели, и добавить нужный mime type было несложно.

Короче, все заработало, а бонусом я выяснил, что в диалоге открытия файлов в GTK не работали иконки, потому что им нужен mimetype. А я и не замечал.

Почему freedesktop не взяли эту либу за основу, я не понимаю. Ведь в OSS так много свободных рук.
6👍3🔥1
Я вчера написал, что не буду дочинивать #pcmanfm, но я был бы не я, если бы не взялся дочинить. Тревожный зуд что "что-то не работает" - штука такая. #debug

Прорвался сквозь сложносочиненный код для детектирования mime types, и выяснил нечто совершенно феерическое.

Если в одну программу слинковать lib/glib + lib/magic, то magic_buffer() начинает возвращать nullptr, а если без lib/glib - то "application/gzip" на данные для случайного .gz архива.

Это очень всрато, и, по сути, такое возможно только если с glib приезжают символы, которые оверрайдят какие-то weak символы в программе.

В процессе поиска я было отчаялся, но нашел флажок MAGIC_DEBUG, который выводил на экран запчасти от того, как работает #libmagic. Я там, почти случайно, понял, что:

* в libmagic есть правила на регулярках

* она их применяет линейным перебором, что, само по себе, пиздец

* libmagic ломается на первом же правиле с регулярками. Тут у меня, что называется, щелкнуло, и пазл сложился.
Вместе с glib приезжает libpcre, в составе которой есть библиотека libpcreposix.a, которая содержит в себе реализацию posix regex.x - regcomp/regexec/etc.

* (к слову, pcmanfm 4 раза дергает функцию для определения mime type для каждого файла, причем 2 раза из них реально считывает данные с диска)

Получалось так, что код собирался с определениями из musl regex.h, а линкер брал символы из pcre.

gdb) b regexec 
Breakpoint 1 at 0x2bf0cf: file src/pcreposix.c, line 328.
(gdb) b regcomp
Breakpoint 2 at 0x2bef33: file src/pcreposix.c, line 274.

Ни к чему хорошему это не приводило, в том числе, ломался и libmagic.

Я это починил, mime types заработали.

Ура? Пьем шампанское? Ага, конечно.

После пересборки world сломался браузер(напомню, что я использую epiphany).

Уже примерно понимая, в чем дело, я поставил breakpoint, и снял вот такой трейc:

#0  0x0000000008650e70 in regexec ()
#1 0x0000000007dd061b in optConfStartElem ()
#2 0x000000000857acb7 in doContent ()
#3 0x0000000008578394 in contentProcessor ()
#4 0x0000000008573ab6 in XML_ParseBuffer ()
#5 0x0000000007dcf4fb in parseOneConfigFile ()
#6 0x0000000007dcf33b in driParseConfigFiles ()
#7 0x0000000007d117a9 in loader_get_user_preferred_fd ()
#8 0x00000000068d74c9 in dri2_initialize_wayland ()
#9 0x00000000068d266a in dri2_initialize ()
#10 0x00000000068c4d99 in eglInitialize ()

Это, конечно, прекрасное. Это реальный случай про "два бага, которые отменяли друг друга".

Потому что, когда в glib была зависимость от pcreposix, ломался разбор конфига в mesa, и поэтому #zink (мой opengl driver) работал just as planned!

А когда я починил регулярки, конфиг начал обрабатываться правильно, и #zink начал глючить c новыми настройками!

Если вы когда-нибудь, зачем-то, хотели увидеть плачущего 40-летнего мужика, вам надо было быть вчера у меня дома.

Что с этим делать, пока непонятно.
😁22🤯5🔥4👍2😢1
(продолжение)

И, знаете, эта система приоритетов работала настолько хорошо, что я уже было собрался писать победный пост, как я загнул #scheduler, и у меня все работает плавнее, чем в macos. Кстати, похвастаюсь, что, без нагрузки это УЖЕ так, помогли все мои облизывания и политик шедулинга, и тюнинг аллокатора, и так далее.

Но, конечно, Linux и тут себя показал в своей красе, и это какой-то леденящий душу пиздец.

Я не буду утомлять подробностями #debug, просто расскажу, что происходило.

- я запускал сборку чего-то тяжелого, оно насыщало все CPU.

- в этот момент заходил на сайт с зависшим JS, процесс браузера(который, напомню, RR) начинал жрать 100% CPU.

В этот момент начинал срабатывать какой-то сраный код в ядре, который позволял загруженному на 100% RR треду периодически прерывать выполнение FIFO треда от композитора. Даже на самом деле слегка не так, система ограничила сверху время для FIFO + RR задач в какой-то процент от CPU, что привело к тому, что FIFO задача иногда reschedule посредине своей работы.

В этот момент появлялась какая-та всратая фраза в dmesg, про включение тротлинга, погуглив которую я и узнал, что это just as planned. Ну, то есть, долбоебы-разработчики позаботились о том, чтобы FIFO тред не мог съесть весь CPU, несмотря на то, что я попросил именно это.

Ссылку не дам, потому что затерялась, а восстанавливать весь setup сейчас лениво. Самое близкое, что нашел - https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_for_real_time/7/html/tuning_guide/real_time_throttling

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

Если вы внимательно прочли мое описание RTOS, то должны согласиться, что такое поведение неприемлемо для RT системы, и, если бы система вела так, как заявлено, то такого эффекта бы не возникало.

Разработчики этой дичи спецкурс моему преподу, конечно, завалили бы.

Короче, TL;DR - выставил я nice для браузера вместо RR, оно, конечно, лучше, чем без nice, но даже и рядом не стояло с правильным, нужным мне, поведением.

#scheduler я пока не победил, но все еще не отчаиваюсь!
👍4
commit -m "better"
Мне тут посоветовали вместо #mosh использовать https://eternalterminal.dev Я не знаю, как оно работает, и, весьма вероятно, не узнаю, потому что это какая-то пионерская поделка. Как-то рассказывал про #kitty, вот, примерно из той же оперы - говнокод, работающий…
Ну я раскопал падение. #debug

https://gist.github.com/pg83/a369133c03715179534c8945c2b6afd6

pg-> /ix/store/q2oDAqRXi4JDSoxV-bin-et-ix/bin/et --help
Remote shell for the busy and impatient
Usage:
et [OPTION...] [user@]hostname[:port]

-h, --help Print help
--version Print version
-u, --username Username


Что тут написано?

* username - булева опция
* пытаемся ее получить как строку
* ловим bad_cast в dynamic_cast
* кидаем его, не имея exception handler
* попадаем в std::terminate, который перенастроен библиотекой логгирования
* она пытается вывести в stderr
* у нее не получается(хрен знает, почему)

Там особо красивый сниппет кода:

   2649      std::stringstream reasonStream;
2650 reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
2651 << " If you wish to disable 'abort on fatal log' please use "
2652 << "el::Loggers::addFlag(el::LoggingFlag::DisableApplicationAbortOnF
2652 atalLog)";
2653 base::utils::abort(1, reasonStream.str());


Но abort игнорит текст:

    116 /// @brief Aborts application due with user-defined status
117 static void abort(int status, const std::string& reason) {
118 // Both status and reason params are there for debugging with tools like gdb etc
119 ELPP_UNUSED(status);
120 ELPP_UNUSED(reason);
121 #if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
122 // Ignore msvc critical error dialog - break instead (on debug mode)
123 _asm int 3
124 #else
125 ::abort();
126 #endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
127 }


* и оно все падает, без внятной диагностики
🌚10😢4🔥3🐳2👍1🍌1🍾1
У меня вчера, внезапно, пропал wifi на ноутбуке.

Ну вот так, посреди закачки, взял и пропал.

Рестарт не помог, кроме того замечательного факта, что в dmesg(после рестарта) не было никакого упоминания слов intel, iw*, etc.

Устройства не было, интерфейса тоже.

Я собрал ведро с диагностикой, добавил дополнительных драйверов, перезагрузился раз 10, в том числе, в live cd от федоры(в нем тоже не работало), и, в какой-то момент обнаружил, что wifi заработал.

Мне кажется, что произошло это в тот момент, когда я вынул type-c кабель питания, и на его место воткнул внешний жесткий диск с федорой. До этого, диск с федорой я втыкал во второй слот type-c.

Гипотеза заключается в том, что контроллер зарядки(а он, напомню, продолжает работать даже после отключения ноутбука по питанию) пришел в какое-то очень странное состояние, "ломавшее" что-то на шине.

В пользу этой гипотезы есть еще тот факт, что с контроллером зарядки у меня явно что-то не так последние пару месяцев, потому что бывает следующее:

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

* контроллер вообще не видит зарядное устройство, зарядка не идет, пока не перевоткнешь шнур

Это все звучит довольно диковато, но я больше не понимаю, как объяснить тот факт, что wifi выключился, когда я включил ноут в зарядку, и починился, когда я его из зарядки вынул, и включил в этот порт какое-то другое устройство.

Зато 2 часа бессмысленного и беспощадного(потому что ничего не понял) #debug, за время которого я узнал кучу бесполезных знаний про сеть в Linux, и про устройства своего ноутбука!

* например, у меня есть кнопка принудительного(аппаратного) отключения тачпада, Fn-F9, сяомишники знатно потешаются над этим фактом в разных там форумах, чуть ли не первый вопрос новичку, не нажал ли он эту кнопку случайно.

* в первый раз в жизни запустил команду "ip a", увидел интерфейс sit0, и разобрался, что это такое(спойлер - вам это не нужно).

Ну и так далее.
🔥8😁6🤔2
commit -m "better"
В продолжении темы регулярных рестартов. У меня завис unbound. Ну завис и завис, где-то в select/poll/etc, не отвечал на запросы и сам ничего не делал. Можно, конечно, побороться с ветряными мельницами, заслать совершенно ничего не говорящий stack trace…
Как говорится, доверяй, но проверяй!

Я тут, случайно, в выводе pstree увидел красивое:

flock---unbound 

Глаз за это зацепился, потому что я сразу подумал, что тут что-то не то, дерево процессов должно было выглядеть так:

flock---timeout---unbound

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

Посмотрел логи - да, действительно, мой вызов timeout не возымел эффекта. Как будто его и не было.

Не буду утомлять себя рассказом про подробности #debug, сразу расскажу, что было.

https://git.busybox.net/busybox/tree/coreutils/timeout.c#n101

Что там написано?

Там написано, что команда timeout в качестве child запускает код, который демонизируется, и, далее следит за временем выполнения основного процесса, а потом основной процесс делает exec на нужную команду.

Это бы работало, если бы слежка выполнялась в прямом потомке основого процесса, но, видимо, чтобы не плодить зомбаков, следит внук, как я написал выше.

А этого внука прибивает мой процесс, следящий за тем, чтобы в системе не было бесхозных процессов.

Починил я это тем, что добавил в цепочку subreaper, https://unix.stackexchange.com/questions/250153/what-is-a-subreaper-process https://github.com/stal-ix/ix/blob/main/pkgs/bin/unbound/runit/ix.sh#L9

Зачем timeout устроен так сложно?

Я не очень понял их объяснение в коде, но, в целом, это довольно понятно, с точки зрения обработки сигналов, чтобы процесс timeout не стоял между parent и выполняющейся командой, и не занимался ерундой по проксированию сигналов.

Пока я не разобрался, что же там происходит, выглядело это ну очень дико.
🤔5👍4🔥2🤡1
Будни #bootstrap.

Я тут, знаете ли, немножко прихуел, и хочу с вами немедленно поделиться.

Думаю, все сталкивались с сообщением от gnu make "clock skew detected", и про то, что сборка может быть не очень хорошей. Происходит это от того, что какие-то файлы оказываются в будущем, и возникает ситуация, что, как не перестраивай цель, она не станет младше, чем ее зависимости.

Обычно это связано с неполадками в системном времени, или в использовании сетевых FS - https://stackoverflow.com/questions/3824500/compiling-c-on-remote-linux-machine-clock-skew-detected-warning

У меня, внезапно, такая ошибка стала случаться очень часто, практически, в любой сборке, использующей gnu make, вот с такой вот диагностикой: https://gist.github.com/pg83/081189d9140288ce21291d88152ce6d2

Это не совсем обычный случай для clock skew - make пишет, что проблема не в том, что файл в будущем, а в том, что его mtime не попадает в некий диапазон. При этом #gnu make пытается быть святее папы римского, а именно, выставляет синтетическое время модификации этого файла куда-то далеко в будущее.

А у меня это не будущее, а самое дальнее прошлое - нулевой timestamp. Я его принудительно выставляю для всех сборочных артефактов, чтобы потом системные timestamp не попадали в зависимые сборки, и не портили бы воспроизводимость - https://github.com/stal-ix/ix/blob/main/pkgs/die/sh.sh#L69-L73.

Все это леденящий душу пиздец очень удивительно, потому что в какой такой range не попадет 0?

Не буду вас томить скучными подробностями #debug, но вот его результат:

https://git.savannah.gnu.org/cgit/make.git/tree/src/filedef.h#n200, копипаста - https://gist.github.com/pg83/4e54f757ce838ba6aaf746b6b9a2b8b3

Что тут написано?

Тут написано, что make резервирует первые три timestamp (0, 1, 2) под какие-то свои нужды. Вот, реально, сука, make считает, что файлов с timestamp < 3 в системе нет, и быть не может.

Задачка со звездочкой - что на выходе получил автор этого текста, когда попытался выставить своим файлам timestamp 1, и 2, и какими словами он обозвал разработчиков этого кода, когда во всем разобрался.
🤯33😁16🤔3👍2👌21
Люблю истории про интересный #debug

https://badcyber.com/dieselgate-but-for-trains-some-heavyweight-hardware-hacking/

Вот, пожалуйста, офигенный текст про недобросовестную компанию-производитель поездов, которая вносила всякого рода вредоносные правки в свой софт, чтобы поезда, произвольным образом, ломались у клиентов, и чтобы клиенты заключали договор техобслуживания только с этой компанией.

Интересный debug included.
🔥16👍64👌2🤡1
Хозяйке на заметку.

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

Вопрос на засыпку - как ведет stdin/stdout в вашей программе grep (просто для примера, можете взять awk, или sed), с точки зрения буферизации?

Далее ответ на этот вопрос. Вернее, не ответ per se, а набор фактов, которые помогут вам на него ответить:

* Стандарт C, и стандарт POSIX оставляют это unspecified. Ну, то есть, in the wild, вы можете встретить любое поведение.

* glibc соблюдает старую юниксовую традицию - если stdout соединен с tty (ну, считайте, программа запущена в interactive shell), то stdout будет line buffered (то есть, как только в буфер пришел \n, его содержимое сбрасывается в файловый дескриптор). Если не соединен, то stdout buffered, а stderr всегда unbuffered (и это правильно, потому что вы хотите видеть последнее сообщение, которое написала программа перед тем, как умереть по SEGFAULT).

* musl - вроде, тоже, но я не смог там быстро найти проверку, которая бы включала line buffered явно.

* дело усложняется тем, что произвольная программа может положиться на поведение этих потоков по умолчанию, а может как позвать setvbuf(чтобы поменять дефолт), так и звать fflush() в нужных местах. При этом, программа может настаивать на повторении вот этой вот традиции UNIX, то есть, для libc, которая не поддерживает такое соглашение, звать fflush() самостоятельно, или не звать, если считает, что libc устроена согласно разумению этой программы.

* все это усугубляется configure скриптами, которые могут неправильно понять default для нижележащей libc.

Короче, вы поняли - in the wild можно встретить почти любую комбинацию этих поведений, и заранее понять это довольно сложно.

Почему я про это решил рассказать?

Очевидно, потому что столкнулся со странным поведением одного скрипта, который по разному себя вел в процессе отладки, и во время работы в production.

Потратил на #debug пару часов, в результате заменил вызов на gnugrep --line-buffered, чтобы уж точно не зависеть от того, какая программа стоит на хосте, и какие в ней дефолты.

Мораль? Да нет ее, как обычно.
🔥20👍9🤝5🤯3🤔1
Будни #bootstrap

Я как-то писал про устройство хеша в своем cas - https://t.iss.one/itpgchannel/575

После https://t.iss.one/itpgchannel/2477 я решил, что хватит экономить на спичках, и взял в путь не 16 символов от хеша, а 22 (вот так вот странно, потому что у меня там base62) - https://github.com/pg83/ix/commit/d4c1c6cb2b0438d918715f73301848f6408531f1 https://github.com/pg83/ix/commit/8bb1e74c10b7185cda6d4092c0d6553d0fafc919

Решил и решил, но, после этого, у меня начала падать в CI сборка ya, и nix.

Падать с одной и той же ошибкой - E2BIG, она же https://github.com/pg83/ix/commit/d4c1c6cb2b0438d918715f73301848f6408531f1, она же "Argument list too long".

Это довольно известная ошибка, она связана с тем, как ядро запускает новый процесс (argc, argv, env передаются через стек вызвающего процесса). Ну и если стека не хватает, то получается вот такая вот хтонь.

То есть, падать стало довольно закономерно - пути стали длиннее, и перестали помещаться в размер стека.

Я про эту проблему знал, поэтому просто увеличил ulimit -s, и стал ждать того, что мой CI добежит до конца.

Но нифига, ошибка продолжила иметь место быть. И, что самое, СУКА, интересное, если я локально запускал в shell ту же команду, что падала в CI, то, после ulimit -s unlimited, локально все работало, а в CI - нет.

Не буду утомлять вас подробностями #debug, тем, как я запускал strace в сборочных нодах, и тем, как я думал, что ошибка в gnu make, потому что там были манипуляции с max stack size (которые я тоже очень элегантно отключил - https://github.com/pg83/ix/blob/main/pkgs/bin/make/proper/ix.sh).

В итоге, все оказалось довольно просто - make просто брал команду, и запускал ее через /bin/sh -c "very long command".

Понимаете, да?

Я напоролся на ограничение размера одного аргумента командной строки, а не на суммарную длину всех аргументов.

Второе лечится через ulimit -s, первое - нет.

Тут же стало понятно, почему локально "все работало".

Потому что интерактивный sh токенизировал эту очень длинную команду, и делал exec('very', 'long', 'command'), а не exec('sh', '-c', 'very long command')!

Для ya я это починил очень изящно - сделал так, что переменные в команде раскрывал не make, а сам shell, для этого оказалось достаточно заменить несколько переменных из $(A) -> $${A}. https://github.com/pg83/ix/blob/main/pkgs/bin/ya/0/preproc.py#L3-L11

А вот nix пока так и не починил, там все очень печально.
🔥16❤‍🔥5💩53🥱3🤮1🐳1
История одного #debug.

https://marcan.st/2017/12/debugging-an-evil-go-runtime-bug/

TL;DR - как определенное сочетание опций сборки ядра и версий GCC ломало go runtime.
👍12🔥9🤡5🥱2🤮1
https://blog.janestreet.com/a-higgs-bugson-in-the-linux-kernel/

История одного #debug, без излишних соплей, люблю такие.

Чувак для воспроизведения бага:

* запилил fuse файловую систему для быстрой генерации контента
* заиспользовал #eBPF, чтобы вывести stacktrace ядра при возникновении ошибки
* написал плагин для wireshark
* взял NFQUEUE, "userspace process for packet filtering", TIL

И все это, буквально, на двух страничках текста.
🔥40🤯5👍43🆒2🤩1
commit -m "better"
rustc_codegen_gcc
#llvmweekly, история одного #debug.

Довольно существенный прогресс у gcc rust codegen (это, напомню, rust, но с оптимизатором от gcc) - https://fractalfir.github.io/generated_html/cg_gcc_bootstrap.html

TL;DR - пара патчей там и тут, и все сошлось. Одна серьезная проблема - inline(always) для рекурсивных функций, и мутки с 128-битными числами.
9👍4🔥2🤯1