У вас есть определённые ожидания от картошки. Вот если она на следующие сутки превратится в труху, вы таки можете пойти в суд.
А вот платформы могут включить обучение AI внезапно. Или просто забанить, потому что алгоритмы что-то начудили. Вот про это отсутствие предсказуемости я и говорю.
Ну и проблема таких больших бесконтрольных платформ в том, что в моменте вас условия могут устраивать, но потом они меняются без спроса, и вы можете отказаться от использования, но платформа продолжает получать бонус от вашего прошлого труда, а вы от неё — уже нет.
Обидно. Paperwhite до сих пор отлично работает, и тут такая подстава. Видимо, придётся загрузить сразу пару десятков книг, чтобы до конца года хватило.
Мы с вами в двух параллельных вселенных живём. Я говорю о том, как сейчас писать программы так, чтобы ошибок было меньше. Разбиение на независимые части и строгие контракты API этих частей как раз уменьшают сложность системы в целом. И это только один из инструментов, есть и другие. Вы же о том, что авторы должны доказывать, что в их программах нет ошибок. Математически доказывать корректность программ, по крайней мере сейчас, очень долго и дорого и экономически не оправдано. И да, требует применения других языков программирования.
Отвечая про переполнение int'а — используйте Rust и safe-функции, переполнение вызовет panic, а не неопределённое поведение. При желании такие функции и в c++ можно реализовать. Да, будет runtime cost.
Также можно делать type safe обёртки с семантикой, например, "это float в границах [0; 1]". И тогда проверка нужна только при создании значений. А, скажем, при перемножении таких чисел уже можно не проверять.
Вы увели дискуссию в сторону от моей оригинальной мысли о том, что std::filesystem не надо использовать напрямую (и, если уж на то пошло, и chrono, и iostream/fstream). Я не пытался раскрыть тему как писать безопасные программы.
Буквально "WinRAR позволял добавлять в архивы пути с ..". Т.е. ровно то, о чём я говорю. И описанный выше способ работы с файлами от таких ошибок полностью спасает.
Не понимаю. Вот, скажем, в моей подсистеме есть ошибка, и специально созданный архив может модифицировать путь. Но я оперирую относительными путями, а мои интерфейсы каталогов не обрабатывают пути "..". И всё, несмотря на ошибку, создать файл где угодно уже не получится. Почему меня это не спасёт, и нужна криптография? И как криптография тут поможет?
Нельзя защититься от всего, но можно проектировать приложения так, чтобы вероятность ошибки была меньше.
Если ты открываешь свои ресурсы, делай это не через ФС, а специальными классами, соответствующими этим ресурсам.
Это утверждение противоречит статье, т.к. мы хотим делать обобщённый код как для вшитых в приложение, так и для реальных файлов. Ну и код работы с ФС мы точно хотим отделить от классов "текстура" и "меш".
Вы, возможно, меня неправильно поняли. Внутри реализации наших интерфейсов мы пользуемся абсолютными путями, но интерфейс каталога никогда не позволяет выходить за его пределы.
Я привёл пример с уязвимостью в WinRAR. Если бы наша подсистема распаковки не могла выходить за пределы каталога, куда мы распаковываем, то и уязвимости бы не было.
То же относится к кэшам, настройкам, ротации логов, которые всегда живут по определённым путям. Но это не только про создание и удаление файлов — даже если мы открываем каталог на чтение, мы ме должны позволять подсистемам читать данные за его пределами.
Также лучше отделить логику про разное местоположение рабочих каталогов на разных ФС от реальной логики работы, а для этого нам опять нужен интерфейс "каталог" и относительные пути. Плюс не надо думать, в каком виде представлять абсолютный путь в Windows.
Но даже первого достаточно, т.к. если мы можем открыть как реальное дерево с файловой системы, так и архив, то абсолютного пути у нас просто нет.
P.S. А ещё относительные пути производительнее, не надо обрабатывать .. и .
Про то, что std::filesystem можно использовать, я бы поспорил. В небольших утилитах — да, пожалуйста. Но вот в чём-то большем лучше скрыть за специальным интерфейсом-обёрткой. Во-первых, такой интерфейс позволит работать с разными реализациями. Хоть с реальной ФС, хоть со временной в памяти, хоть с zip-архивами. Во-вторых, он позволит проще писать unit-тесты, с нормальными mock'ами и без медленного похода на реальную ФС. В-третьих, этот интерфейс должен позволять компоненту обращаться к файлам и каталогам только по относительному пути, не позволяя выйти за ограничения, заданные вызывающим кодом, и увеличивая безопасность приложения в целом (тут можно вспомнить WinRAR и недавний CVE-2025-6218). Реализация для реальных ФС может быть сделана и поверх std::filesystem, но она не будет самой эффективной. Возможно, правильнее потратить пару недель и сделать несколько реализаций для нужных ОС.
У вас есть определённые ожидания от картошки. Вот если она на следующие сутки превратится в труху, вы таки можете пойти в суд.
А вот платформы могут включить обучение AI внезапно. Или просто забанить, потому что алгоритмы что-то начудили. Вот про это отсутствие предсказуемости я и говорю.
Но модели лучше существуют, тот же Bluesky.
Ну и проблема таких больших бесконтрольных платформ в том, что в моменте вас условия могут устраивать, но потом они меняются без спроса, и вы можете отказаться от использования, но платформа продолжает получать бонус от вашего прошлого труда, а вы от неё — уже нет.
Канцлер в Германии плюс-минус соответствует президенту РФ, а президент Германии вообще не важная фигура.
Видимо, так и буду делать. Но удобно было просто отправлять на почту.
Обидно. Paperwhite до сих пор отлично работает, и тут такая подстава. Видимо, придётся загрузить сразу пару десятков книг, чтобы до конца года хватило.
И мы усложняем код только для того, чтобы переменные были фиксированные. Убрали сложность в одном месте, но добавили в другом (и, ИМХО, больше).
Из какого города? В Хельсинки вполне себе чистят.
Весной убирают
А в чём отличие? Полностью идентичный код.
Я репортил баг в версии 0.3 в начале 2008 года. Удивлён, что сейчас только версия 0.7.
Мы с вами в двух параллельных вселенных живём. Я говорю о том, как сейчас писать программы так, чтобы ошибок было меньше. Разбиение на независимые части и строгие контракты API этих частей как раз уменьшают сложность системы в целом. И это только один из инструментов, есть и другие. Вы же о том, что авторы должны доказывать, что в их программах нет ошибок. Математически доказывать корректность программ, по крайней мере сейчас, очень долго и дорого и экономически не оправдано. И да, требует применения других языков программирования.
Отвечая про переполнение int'а — используйте Rust и safe-функции, переполнение вызовет panic, а не неопределённое поведение. При желании такие функции и в c++ можно реализовать. Да, будет runtime cost.
Также можно делать type safe обёртки с семантикой, например, "это float в границах [0; 1]". И тогда проверка нужна только при создании значений. А, скажем, при перемножении таких чисел уже можно не проверять.
Вы увели дискуссию в сторону от моей оригинальной мысли о том, что std::filesystem не надо использовать напрямую (и, если уж на то пошло, и chrono, и iostream/fstream). Я не пытался раскрыть тему как писать безопасные программы.
https://github.com/absholi7ly/CVE-2025-6218-WinRAR-Directory-Traversal-RCE?tab=readme-ov-file#2-root-cause-explanation
Буквально "WinRAR позволял добавлять в архивы пути с ..". Т.е. ровно то, о чём я говорю. И описанный выше способ работы с файлами от таких ошибок полностью спасает.
Не понимаю. Вот, скажем, в моей подсистеме есть ошибка, и специально созданный архив может модифицировать путь. Но я оперирую относительными путями, а мои интерфейсы каталогов не обрабатывают пути "..". И всё, несмотря на ошибку, создать файл где угодно уже не получится. Почему меня это не спасёт, и нужна криптография? И как криптография тут поможет?
Нельзя защититься от всего, но можно проектировать приложения так, чтобы вероятность ошибки была меньше.
Это утверждение противоречит статье, т.к. мы хотим делать обобщённый код как для вшитых в приложение, так и для реальных файлов. Ну и код работы с ФС мы точно хотим отделить от классов "текстура" и "меш".
Вы, возможно, меня неправильно поняли. Внутри реализации наших интерфейсов мы пользуемся абсолютными путями, но интерфейс каталога никогда не позволяет выходить за его пределы.
Я привёл пример с уязвимостью в WinRAR. Если бы наша подсистема распаковки не могла выходить за пределы каталога, куда мы распаковываем, то и уязвимости бы не было.
То же относится к кэшам, настройкам, ротации логов, которые всегда живут по определённым путям. Но это не только про создание и удаление файлов — даже если мы открываем каталог на чтение, мы ме должны позволять подсистемам читать данные за его пределами.
Также лучше отделить логику про разное местоположение рабочих каталогов на разных ФС от реальной логики работы, а для этого нам опять нужен интерфейс "каталог" и относительные пути. Плюс не надо думать, в каком виде представлять абсолютный путь в Windows.
Но даже первого достаточно, т.к. если мы можем открыть как реальное дерево с файловой системы, так и архив, то абсолютного пути у нас просто нет.
P.S. А ещё относительные пути производительнее, не надо обрабатывать .. и .
Нам может быть нужно больше всего — мапить в память, создавать и удалять файлы, смещать файловые указатели. Стримы очень ограниченные.
Про то, что std::filesystem можно использовать, я бы поспорил. В небольших утилитах — да, пожалуйста. Но вот в чём-то большем лучше скрыть за специальным интерфейсом-обёрткой.
Во-первых, такой интерфейс позволит работать с разными реализациями. Хоть с реальной ФС, хоть со временной в памяти, хоть с zip-архивами.
Во-вторых, он позволит проще писать unit-тесты, с нормальными mock'ами и без медленного похода на реальную ФС.
В-третьих, этот интерфейс должен позволять компоненту обращаться к файлам и каталогам только по относительному пути, не позволяя выйти за ограничения, заданные вызывающим кодом, и увеличивая безопасность приложения в целом (тут можно вспомнить WinRAR и недавний CVE-2025-6218).
Реализация для реальных ФС может быть сделана и поверх std::filesystem, но она не будет самой эффективной. Возможно, правильнее потратить пару недель и сделать несколько реализаций для нужных ОС.
В C++ это explicit конструкторы типов, которые потом не позволят одно к другому неявно привести.
Или, если не позволяет,
bank.transfer(SenderId(1), ReceiverId(2), Amount(1200), Fee(1.2));Я их бризером пользовался, он вполне норм. До него вечно была проблема, что окно откроешь, а кто-то снизу решил закурить.
>Вы не замечали, что после отпуска ваш СО2 сенсор показывает какие-то нехорошие большие значения и только со временем они становятся нормальными?
Не замечал.