Telegram Group Search
Please open Telegram to view this post
VIEW IN TELEGRAM
Скомпилируется ли такой код на Си?

И если нет, то почему?

#include <sys/fcntl.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>

typedef struct {
int mtime;
int size;
} Storage;

void load(Storage *st) {
scanf("%d%d", &st->mtime, &st->size);
}

int main() {
Storage st;
load(&st);
int st_mtime = st.mtime;
int st_size = st.size;
printf("st_mtime = %d, st_size = %d\n", st_mtime, st_size);
return 0;
}


Примечания:
- компилируем под GNU/Linux на x86_64 с glibc и компилятором gcc любой не очень древней версии
- можно убедиться, что код содержит только ASCII-символы и не содержит длинных последовательностей пробелов (то есть приколов вроде «вот здесь используется кириллическое е вместо e латиницей, попались!» в этом коде нет)
- в дополнение к предыдущему пункту: если вы перенаберете код в своей любимой IDE так, как его видите в посте, то он будет абсолютно идентичен

Догадки можно писать в комментарии :)
Гепардово гнездо
Скомпилируется ли такой код на Си? И если нет, то почему? #include <sys/fcntl.h> #include <sys/types.h> #include <errno.h> #include <unistd.h> #include <stdio.h> typedef struct { int mtime; int size; } Storage; void load(Storage *st) { scanf("%d%d"…
Ответ такой: код не скомпилируется. Даже несмотря на то, что он выглядит довольно безобидно, и явно никаких ошибок не видно.

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

Где-то в недрах системных заголовков есть struct stat (здесь он прилетает через #include <sys/fcntl.h>) — структура с метаданными файла, которая используется в системном вызове stat. Изначально времена доступа к файлам хранились в этой структуре в полях st_mtime, st_atime, st_ctime в виде UNIX таймстемпа с точностью до секунды. Затем точность повысили до наносекунд и стали использовать struct timespec для задания времени (поля st_atim, st_ctim, st_mtim). А чтобы не ломать обратную совместимость для тех программ, которые про наносекундную точность ничего не знают, вставили вот такой вот костыль:

       #define st_atime  st_atim.tv_sec  /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec


И теперь выходит, что объявление переменной st_mtime дает ошибку, поскольку уже объявлен макрос ровно с таким же именем, и препроцессор раскрывает st_mtime в st_mtim.tv_sec
Please open Telegram to view this post
VIEW IN TELEGRAM
Про throwing values

Расскажу коротко про throwing values (они же иногда называются herbceptions, потому что предложил их Herb Sutter). Полностью прочитать можно здесь, а я лишь отмечу основные моменты:
* функции, которые кидают исключение, помечены как throws, при этом по сути они возвращают исключение просто как значение, в регистрах (почти как Result<T, E> в Rust и std::expected<>)
* такие «исключения» пробрасываются автоматически и синтаксически ловятся try/catch как обычные, хотя на самом деле в этом случае раскрутка стека не используется. Конечно, можно их так не реализовывать, а сделать почти как в Rust и требовать подобие оператора ?, чтобы явно пробрасывать ошибку
* все исключения лежат в типе std::error размером с два указателя (чем-то похоже на гошный тип error и существующий в C++ std::error_code). Первая половина — это категория ошибки, а вторая — ее содержание (просто код ошибки для простых случаев, указатель на подробное описание для сложных, в зависимости от категории). В статье приводится также мотивация в пользу единого типа ошибок std::error вместо кучи разных типов как в текущей реализации исключений

Также в proposal'е предлагается добавить _Either(T, E) в Си для поддержания совместимости, а еще оптимизации вида «юзать регистр флагов, чтобы понять, вернулась ошибка или значение».

На картинке выше (которую я честно украл из статьи) показывается сравнение синтаксиса throwing values и std::expected<>, где видно, что код со throwing values выглядит гораздо проще.

Наверное, можно было бы еще поговорить на эту тему, но я вас уже и так закидал кучей разного текста на сегодня, поэтому остановимся здесь :)
Драма в двух актах

(оригинал здесь: https://github.com/nim-lang/Nim/issues/23796)

(это я так законтрибутил фикс своей баги в Nim, а потом оказалось, что мой фикс ломает существующий код в специфичном сценарии)
Недавно наткнулся на интересный пост про онлайн-безопасность (а точнее, ее отсутствие) в Южной Корее:

https://palant.info/2023/01/02/south-koreas-online-security-dead-end/

Если кратко:
- по историческим причинам крупные банки вместо TLS используют свою криптографию и протоколы для организации шифрованного соединения
- чтобы эти протоколы использовать, необходимо ставить сторонние расширения или приложения
- сами эти приложения защищены плохо и используют устаревшие и уязвимые библиотеки
- по этой же причине долгое время обязательно требовался Internet Explorer, но ситуация с тех пор поменялась
- никто эту проблему так и не решил (по крайней мере, на момент начала 2023 года, когда этот пост вышел)

Если честно, я шокирован, что такая ситуация может быть в целой стране, причем довольно развитой и технологичной
Please open Telegram to view this post
VIEW IN TELEGRAM
Есть такой сайт в интернетах: https://tylervigen.com/spurious-correlations. Это наглядная демонстрация того, что корреляция не обязательно означает причинно-следственную связь, и может быть лишь удачным совпадением.

Работает он очень просто:
* собираем много разных графиков на много разных тем (около 20'000 штук!)
* попарно пробуем вычислить корреляцию между ними
* собираем все случаи, когда величины коррелируют с хорошей такой достоверностью
* публикуем :)

Сайт существует довольно давно, какое-то время назад он был сломан. Сегодня я зашел и увидел, что он снова работает и получил обновление в духе нынешнего времени:
* добавились «объяснения» корреляций с помощью LLM'ок
* также LLM'ками генерятся «научные» статьи вокруг найденной корреляции

Получилась еще и довольно забавная иллюстрация того, как можно «объяснить» все, что угодно :)
Please open Telegram to view this post
VIEW IN TELEGRAM
Чем я еще заnimался

Расскажу, пожалуй, еще одну интересную историю про Nim.

Но сначала познакомлю вас с действующими лицами сего повествования:

* nim: компилятор Nim, лучшего языка программирования в мире. Можете считать примерным аналогом rustc из мира Rust.
* nimble: пакетный менеждер для языка Nim. Примерный аналог cargo из мира Rust.
* choosenim: утилита, которая умеет устанавливать nim и nimble нужных версий, а также обновлять их. Примерный аналог rustup из мира Rust.

Теперь можно начинать рассказ.

Однажды я заметил, что мой CI-пайплайн программы на Nim замедлился аж на целых пять минут! Все мы прекрасно помним xz и Jia Tan, и как из-за тормозов openssh был найден очень хорошо спрятанный бэкдор. Но в случае с openssh замедление составляло сотни миллисекунд, а здесь — аж целых пять минут! Паранойя зашкаливает, желание разобраться — еще больше.

В итоге, используя метод grep'а и внимательного чтения нагрепанного кода (очень полезный метод, кстати), я выяснил вот что:

* choosenim скачивает бинарники nim и nimble (и еще кучу разных других нужных вещей), и распаковывает их
* перед тем, как создать ссылки на распакованные бинарники в нужной папке, choosenim зовет nimble --version, чтобы напечатать предупреждение, если версия nimble слишком древняя и не поддерживается
* nimble перед тем, как показать свою версию, проверяет свое окружение, и обнаруживает, что компилятора nim нет на месте
* далее nimble пытается исправить это безобразие. Для этого он сам клонирует репу с компилятором nim и собирает его из исходников!
* сборка компилятора — конечно же, дело небыстрое, и занимает те самые пять минут. Скажем лишь спасибо, что компилятор собирается довольно быстро, и не приходится ждать часами.

В общем, предсказуемо никакого Jia Tan'а здесь не оказалось, зато оказался банальный баг. А с багами поступают обычно просто: репортят и ждут фикса. Пофиксили его, впрочем, быстро и легко: теперь --version лишь выводит версию и больше ничего сделать не пытается.

Выводы из этой истории делайте сами.
Я написал очень длинный и очень интересный текст про Юникод. Поскольку в Telegram пост такого размера не помещается, выложил на сайт:

https://blo.gepar.do/v0/unicode.html

Все бегом читать :)
Вдогонку про Юникод и Rust

Во-первых, спасибо всем, кто читал и распространял мой пост про Юникод :) Формат с большими текстами на сайте оказался, как видно, довольно неплох, и надо будет когда-нибудь попробовать его еще раз…

Во-вторых, хотелось бы рассказать еще немного про крейт unicode_categories в Rust, который упоминался в посте. Крейт этот примечателен вот чем:
* С одной стороны, он заброшен и не развивается (последний релиз в 2016 году, последний коммит в репу — в 2021), а еще имеет версию 0.1.1 и не поддерживает новые версии Юникода.
* С другой стороны, он очень активно используется: под 80'000 скачиваний ежедневно, занимает 623 место по общему числу скачиваний, и от него зависят многие другие крейты. Какое-то время назад он даже использовался в rustfmt, но, к счастью, его там заменили на более современный unicode-properties.

Выводы делайте сами. Мне вспоминается лишь https://xkcd.com/2347 :)
This media is not supported in your browser
VIEW IN TELEGRAM
Про переписывание истории

В баше (а точнее, в GNU Readline, который используется башом), есть довольно странная фича: историю команд можно редактировать!

Делается это так:
* нажимаем клавишу ↑, доматываем до команды, которую хотим отредактировать
* редактируем команду
* нажимаем клавишу ↓, доматываем до конца
* готово :)

Наглядную демонстрацию можно видеть на видео выше.

Я на эту «фичу» неумышленно натыкался много раз, и, сам того не зная, редактировал историю. А потом недоумевал, почему у меня при вызове history часть строк оказывались пустыми.

Как это отключить? Можно почитать, например, здесь. Если коротко, то надо в домашней папке создать файл с названием .inputrc и поместить в него такие строчки:

$include /etc/inputrc
set revert-all-at-newline on
Еще про проклятые фичи баша

https://yossarian.net/til/post/some-surprising-code-execution-sources-in-bash

tl;dr: вот эта функция на баше при передаче «правильного» аргумента может привести к выполнению произвольного кода:
function guess() {
num="${1}"
if [[ "${num}" -eq 42 ]]
then
echo "Correct"
else
echo "Wrong"
fi
}


Мораль проста: не пишите на баше не передавайте в bash-скрипты недоверенные данные
https://www.ryanliptak.com/blog/every-rc-exe-bug-quirk-probably/

Не знаю, как вы, а я просто обожаю такие посты.

Здесь автор попытался написать альтернативную реализацию компилятора ресурсов Windows. Это программа, которая принимает текстовый .rc файл с описанием менюшек, кнопочек, окошек, иконок, курсоров и прочего, и компилирует это описание в бинарный .res файл, который потом встраивается в бинарник приложения под Windows.

Альтернативных реализаций компилятора ресурсов много, но у автора была цель, которой не добивались остальные: написать все на новом модном современном Zig как можно точнее сохранить совместимость с оригинальной версией от Microsoft, вплоть до багов и незадокументированного поведения.

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

Пост длинный; если хотите посмотреть только самое интересное, можно поискать по странице по словам utterly baffling. Если же у вас много времени и вам не лень, можно прочесть и все :)
Сегодня читал про то, как Debian везде перешел на 64-х битный time_t. Изменение войдет в релиз Debian 13 (будет выпущен летом/осенью следующего года).

Проблема очень важная, ведь в 2038 году 32-х битный time_t переполнится, и многие компьютеры по всему миру не смогут узнать правильное время! А учитывая, что до 2038 года осталось немногим более 13 лет (осталось всего-то пережить пару эпидемий, восстание машин и ядерную войну), то проблему надо как-то решать!

Конечно же, не все настолько драматично. Большинство процессоров в мире уже давно как 64-х битные, и юзают «правильный», 64-х битный time_t по умолчанию почти везде. Но старые, 32-х битные системы все еще существуют, и для них надо что-то придумать.

Итак, для решения проблемы 2038 года в Debian приняли ряд компромиссных решений странных костылей. Следите внимательно, чтобы не запутаться :)
* Для 64-х битных систем time_t уже и так 64-х битный, поэтому весь «переход» заключается лишь в переименовании пакетов (например, libcurl4libcurl4t64). Новые пакеты с t64 при этом «предоставляют» пакет со старым именем, чтобы сторонние программы не заметили поломки ABI, не получили неудовлетворенных зависмостей и продолжали себе спокойно работать.
* Для i386 (так в Debian называют 32-х битные Intel'ы) пакеты тоже получили суффикс t64, но time_t там так и остался 32-х битным 🐳🐳 Как и на 64-х битных архитектурах, новые пакеты с t64 «предоставляют» старые. Так сделано, потому что либы под i386 очень уж часто юзаются для запуска старых программ, которые невозможно перекомпилить, поэтому поломка ABI для них нежелательна. А суффикс t64 все равно приписали, видимо, потому что переименование пакетов сделали для всех архитектур сразу.
* Для других 32-х битных архитектур (armel, armhf) пакеты тоже получили t64 суффикс, но при этом они получили еще и 64-х битный time_t.

Кстати, в Ubuntu этот переход тоже проделали, и пакеты с суффиксом t64 уже есть в последнем LTS-релизе, 24.04.

Выводы из всей этой истории делайте сами.
https://habr.com/ru/post/472970/

Статья 2019 года, то есть довольно старая, с учетом того, сколько всего разного с тех пор добавили в Telegram (включая комментарии, истории и анимированных китов 🐳)

В ней описывается куча странных технических решений и множество костылей в Telegram и его протоколе MTProto.

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

К сожалению, слова «часть 1» в заголовке — неправда, и вторая часть так и не вышла :(
Please open Telegram to view this post
VIEW IN TELEGRAM
2024/12/25 12:08:55
Back to Top
HTML Embed Code: