PVS-Studio: поиск ошибок в коде
Проверили Elasticsearch и нашли ошибку. Сможете отыскать ее в этом фрагменте? #java #ошибка
#prog #java #бомбёжкипост
В статье от PVS-Studio пишут про ошибку, найденную анализатором. Именно, в строке 8 исключение создаётся, но не выбрасывается. Я, признаться честно, это пропустил, но заметил (как и другой комментатор в оригинальном канале) другую ошибку: в строке 6 записывается индекс символа
Я решил было написать код на Rust и продемонстрировать, насколько сложнее там допустить такую ошибку банально из-за более вменяемого API, но потом я решил глянуть на этот метод немного более широко. Именно, что этот код вообще делает? Он на каждый вызов разбирает строку от начала до конца, чтобы найти нужную подстроку. Он делает лишнюю работу, если вызывается больше хотя бы раза. Разумно было бы сделать этот разбор только один раз и сложить результаты в словарь. Это убрало бы оверхед разбора и заодно переместило бы валидацию значений с каждого вызова метода на единственное создание мапы.
Я решил посмотреть, как этот метод используется. И после этого у меня начало бомбить.
Так как это приватный метод, все его использования должны быть в этом же файле. И действительно, этот метод вызывается два раза, в package-private геттере getStorageEndpoint. И знаете, с чем он вызывается? С константами
А вот и нет! Именно, строка, разбираемая в
Но и это ещё не всё. В методе
P. S.: посылаю лучи ненависти разработчикам нового UI GitHub, где визуальное отображения выделения текста не совпадает с реально выделенным текстом, а ссылки на результаты поиска символа не всегда переходят к нужной строке.
В статье от PVS-Studio пишут про ошибку, найденную анализатором. Именно, в строке 8 исключение создаётся, но не выбрасывается. Я, признаться честно, это пропустил, но заметил (как и другой комментатор в оригинальном канале) другую ошибку: в строке 6 записывается индекс символа
= в строке setting, которая является обрезанной settings[i], но в условии в строке 7 этот индекс проверяется в settings[i], изначальной, необрезанной строке. Намерение этого кода в данном блоке заключается в том, чтобы разбить строку на две половины до и после = и убедиться, что обе части непустые, однако из-за ошибки в условии проверка может пропустить пустую строку после =.Я решил было написать код на Rust и продемонстрировать, насколько сложнее там допустить такую ошибку банально из-за более вменяемого API, но потом я решил глянуть на этот метод немного более широко. Именно, что этот код вообще делает? Он на каждый вызов разбирает строку от начала до конца, чтобы найти нужную подстроку. Он делает лишнюю работу, если вызывается больше хотя бы раза. Разумно было бы сделать этот разбор только один раз и сложить результаты в словарь. Это убрало бы оверхед разбора и заодно переместило бы валидацию значений с каждого вызова метода на единственное создание мапы.
Я решил посмотреть, как этот метод используется. И после этого у меня начало бомбить.
Так как это приватный метод, все его использования должны быть в этом же файле. И действительно, этот метод вызывается два раза, в package-private геттере getStorageEndpoint. И знаете, с чем он вызывается? С константами
BLOB_ENDPOINT_NAME и BLOB_SECONDARY_ENDPOINT_NAME, определёнными несколькими строками выше, как "BlobEndpoint" и "BlobSecondaryEndpoint"! Окей, два вызова — это не настолько плохо (при условии, что сам getStorageEndpoint вызывается один раз), но, вероятно, строка для разбора передаётся извне, поэтому сам разбор имеет смысл?А вот и нет! Именно, строка, разбираемая в
getProperty — это результат вызова getConnectionString, тривиального геттера, возвращающего поле connectString. Значение этого поля, ожидаемо, выставляется в конструкторе (типа AzureStorageSettings), через вызов статического метода buildConnectString. Этот метод составляет строку вида key=value;key=value;... из переданных аргументов, и в число этих аргументов входят endpoint (который записывается после BlobEndpoint=) и secondaryEndpoint (который записывается после BlobSecondaryEndpoint=). Знакомые строки? Да, это именно те константы, которые используются для лукапа в getStorageEndpoint. Иными словами, в getStorageEndpoint вызывается код, который разбирает строку, чтобы получить оттуда значения, которые были переданы в конструктор типа напрямую! Просто сохранив значения аргументов, можно было бы выкинуть весь метод getProperty целиком и заменить его вызовы на два доступа к полям.Но и это ещё не всё. В методе
getStorageEndpoint возвращается запись StorageEndpoint, которая является просто парой строк. Даже имена полей дают понять, что эти два значения — URI. Хранятся ли они в виде URI (этот тип даже импортируется в начале файла)? Нет, они хранятся в типе String. Как тогда код валидирует, что это действительно URI? Никак... Точнее, не всегда. Именно, StorageEndpoint создаётся в двух местах в этом файле, как раз в методе getStorageEndpoint. В первом случае строки передаются напрямую, а во втором передаются результаты вызова метода deriveURIFromSettings. Этот метод конструирует строку из полей AzureStorageSettings, а в конце там вот такой восхитительный код: try {
return new URI(uriString).toString(); // validates the URI
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}URI создаётся только для того, чтобы немедленно перевести его в строку и потерять гарантии валидности!P. S.: посылаю лучи ненависти разработчикам нового UI GitHub, где визуальное отображения выделения текста не совпадает с реально выделенным текстом, а ссылки на результаты поиска символа не всегда переходят к нужной строке.
🔥15😁7👍2❤1🫡1
Блог*
(надо, кстати, написать про релиз)
#prog #rust #rustreleasenotes
Вышла версия Rust 1.97.0! Как всегда, тут только части, а остальное там.
▪️Для манглинга символов теперь используется собственная версия манглинга v0. Изначально rustc использовал схему манглинга, описанную в Itanium ABI, но со временем эта схема была закостылена для поддержки Rust-специфичных фич и потому всё равно требовала специальной поддержки со стороны отладчиков.
Новая схема обладает рядом преимуществ. Среди них — в отличие от старой схемы, не теряется информация об обобщённых аргументах, и в символ не протекает хэш из компилятора, который за пределами самого компилятора не имеет смысла.
▪️cargo теперь может контролировать влияние предупреждений на компиляцию, в частности, останавливать компиляцию при их наличии. До этого соответствующую настройку нужно было прокидывать непосредственно до rustc.
▪️Стабилизировали несколько методов на примитивных числовых типах для битосовокупления: highest_one, isolate_highest_one, lowest_one, isolate_lowest_one и bit_width (этот только на беззнаковых). Эти же методы доступны и на
▪️Компилятор теперь предупреждает, когда тип выводится, как f32, если о нём известно только то, что он реализует From<{float}>. Сейчас тип выводится однозначно, но после добавления примитивного типа
▪️На Windows попытка обратиться к сокету после вызова shutdown теперь возвращает ошибку с io::ErrorKind::BrokenPipe.
Вышла версия Rust 1.97.0! Как всегда, тут только части, а остальное там.
▪️Для манглинга символов теперь используется собственная версия манглинга v0. Изначально rustc использовал схему манглинга, описанную в Itanium ABI, но со временем эта схема была закостылена для поддержки Rust-специфичных фич и потому всё равно требовала специальной поддержки со стороны отладчиков.
Новая схема обладает рядом преимуществ. Среди них — в отличие от старой схемы, не теряется информация об обобщённых аргументах, и в символ не протекает хэш из компилятора, который за пределами самого компилятора не имеет смысла.
▪️cargo теперь может контролировать влияние предупреждений на компиляцию, в частности, останавливать компиляцию при их наличии. До этого соответствующую настройку нужно было прокидывать непосредственно до rustc.
▪️Result<T, Uninhabited> и ControlFlow<Uninhabited, T> теперь триггерят линт must_use, если им помечен сам T.▪️Добавили новый линт, который предупреждает о неиспользуемых pub-определениях в бинарных крейтах (к сожалению, allow by default)▪️Добавили (точнее, стабилизировали) cfg(target_has_atomic_equal_alignment = N), который позволяет удостовериться, что примитивный численный тип указанной ширины и соответствующий Atomic*-тип имеют одинаковое выравнивание. Да, это не всегда так, особенно на 32-битных платформах.▪️Стабилизировали несколько методов на примитивных числовых типах для битосовокупления: highest_one, isolate_highest_one, lowest_one, isolate_lowest_one и bit_width (этот только на беззнаковых). Эти же методы доступны и на
NonZero.▪️Компилятор теперь предупреждает, когда тип выводится, как f32, если о нём известно только то, что он реализует From<{float}>. Сейчас тип выводится однозначно, но после добавления примитивного типа
f16 (да, на это есть планы) он уже перестанет таким быть.▪️На Windows попытка обратиться к сокету после вызова shutdown теперь возвращает ошибку с io::ErrorKind::BrokenPipe.
❤5
Forwarded from Другая Природа
Весьма самодостаточным будет сказать, что из драконьей пасти вырывался флогистон.
❤🔥1🤔1
Forwarded from Спасибо, Док!
Мужчинам полезно, а женщинам крайне интересно
У нас в культуре писать стоя это незыблемый символ маскулинности. Мальчиков с детства учат попадать точно в цель, а привычка сидеть на унитазе часто высмеивается как что то исключительно женское.
Гендерные стереотипы предлагаю отложить в сторону и посмотреть на процесс мочеиспускания чисто с урологической точки зрения.
Женщины сейчас будут торжествовать (и дело не только в чистом стульчаке), а мужчинам желательно переосмыслить свои туалетные ритуалы.
Чтобы мочевой пузырь полностью и без усилий опорожнился, нужно выполнить одно главное условие - максимально расслабить мышцы тазового дна.
А что происходит, когда мужчина стоит? Чтобы удерживать вертикальное положение тела, мышцы ног, пресса, спины и того самого тазового дна находятся в постоянном фоновом тонусе. Сфинктеру приходится работать с усилием, преодолевая это напряжение.
Когда мужчина садится, постуральные (удерживающие позу) мышцы выключаются. Тазовое дно полностью расслабляется, и мочевой пузырь спокойно сдувается, как воздушный шарик, не оставляя внутри ни капли.
Поверьте, это не просто красивые теории. В авторитетнейшем научном журнале PLOS One был опубликован крупный метаанализ, который поставил точку в этом вопросе.
Если молодому и абсолютно здоровому парню физиологически без разницы, как ходить в туалет, то для мужчин старше 40 лет или тех, у кого есть хоть малейшие проблемы с простатой (аденома, простатит), поза сидя имеет критическое значение.
Ученые статистически верифицировали, что в положении сидя кратно снижается объем остаточной мочи.
А остаточная моча - это та самая теплая питательная лужица, которая остается на дне пузыря, если он не сократился до конца. Именно в ней потом размножаются бактерии, приводя к хроническим циститам, простатитам и ночным забегам в туалет.
Про преимущество женщин я не забыл!
Физики из Университета Бригама Янга провели прикольный эксперимент со скоростными камерами и выяснили: при мочеиспускании стоя (даже если вы снайпер и целитесь строго в воду) образуются тысячи невидимых глазу микрокапель. Этот аэрозоль разлетается в радиусе до 1,5 метров, оседая на стенах, полотенцах и ваших зубных щетках.
Есть над чем подумать.
Спасибо, Док! в MAX
У нас в культуре писать стоя это незыблемый символ маскулинности. Мальчиков с детства учат попадать точно в цель, а привычка сидеть на унитазе часто высмеивается как что то исключительно женское.
Гендерные стереотипы предлагаю отложить в сторону и посмотреть на процесс мочеиспускания чисто с урологической точки зрения.
Женщины сейчас будут торжествовать (и дело не только в чистом стульчаке), а мужчинам желательно переосмыслить свои туалетные ритуалы.
Чтобы мочевой пузырь полностью и без усилий опорожнился, нужно выполнить одно главное условие - максимально расслабить мышцы тазового дна.
А что происходит, когда мужчина стоит? Чтобы удерживать вертикальное положение тела, мышцы ног, пресса, спины и того самого тазового дна находятся в постоянном фоновом тонусе. Сфинктеру приходится работать с усилием, преодолевая это напряжение.
Когда мужчина садится, постуральные (удерживающие позу) мышцы выключаются. Тазовое дно полностью расслабляется, и мочевой пузырь спокойно сдувается, как воздушный шарик, не оставляя внутри ни капли.
Поверьте, это не просто красивые теории. В авторитетнейшем научном журнале PLOS One был опубликован крупный метаанализ, который поставил точку в этом вопросе.
Если молодому и абсолютно здоровому парню физиологически без разницы, как ходить в туалет, то для мужчин старше 40 лет или тех, у кого есть хоть малейшие проблемы с простатой (аденома, простатит), поза сидя имеет критическое значение.
Ученые статистически верифицировали, что в положении сидя кратно снижается объем остаточной мочи.
А остаточная моча - это та самая теплая питательная лужица, которая остается на дне пузыря, если он не сократился до конца. Именно в ней потом размножаются бактерии, приводя к хроническим циститам, простатитам и ночным забегам в туалет.
Про преимущество женщин я не забыл!
Физики из Университета Бригама Янга провели прикольный эксперимент со скоростными камерами и выяснили: при мочеиспускании стоя (даже если вы снайпер и целитесь строго в воду) образуются тысячи невидимых глазу микрокапель. Этот аэрозоль разлетается в радиусе до 1,5 метров, оседая на стенах, полотенцах и ваших зубных щетках.
Есть над чем подумать.
Спасибо, Док! в MAX
👍13❤4🤔1🤮1👌1
However, we can make the fopen function appear to be pure, at least to certain observers, by ensconcing it in another function that hides the side effect.
Это из критики второй редакции Clean code, но цитата из книги прямая. Дядя Боб не умеет программировать
void openAndDo(char* fileName, void (*doTo)(FILE*)) {
FILE* f = fopen(fileName, "r+");
doTo(f);
fclose(f);
}Это из критики второй редакции Clean code, но цитата из книги прямая. Дядя Боб не умеет программировать
🤣20👎1🤮1💩1🫡1
#prog #article
Abstraction: Not What You Think It Is
TL;DR: абстракции — это сугубо умозрительные конструкции, которые не отображаются ни на какую конкретную конструкцию языка программирования напрямую, и в силу своей природы разные абстракции можно строить, не трогая исходный код вообще. Перед тем, как показать определение, автор также перечисляет вещи, которые часто называют абстракцией, но не являются ей в смысле приведённого им определения.
Abstraction: Not What You Think It Is
As the quoted writers show, people do not even agree what abstraction means. <...>
This situation is particularly sad for me as someone with a background in PL theory. There are a lot of topics in software engineering that are the result of accumulated intuition over decades. But we've had a pretty good definition of abstraction since 1977, originally in the context of program analysis, and — I claim — it actually translates quite well into a precise definition of “abstraction” in engineering.
TL;DR: абстракции — это сугубо умозрительные конструкции, которые не отображаются ни на какую конкретную конструкцию языка программирования напрямую, и в силу своей природы разные абстракции можно строить, не трогая исходный код вообще. Перед тем, как показать определение, автор также перечисляет вещи, которые часто называют абстракцией, но не являются ей в смысле приведённого им определения.
👍3❤1❤🔥1
Блог*
#game Рекомендую сию чудесную вещь — Годвилль. Играю вот уже... Семь с половиной лет. youtube.com/watch?v=lEMz9mUWAak
Тупае на днях стукнуло 10 лет
🤔2👌1
#prog #article
pre-commit hooks are fundamentally broken
pre-commit hooks are fundamentally broken
Please just don't use pre-commit hooks. Use pre-push instead. pre-push hooks nearly avoid all of these issues.
👍11🤔1💯1
#rust
crates.io: development update
Из заметного: на crates.io теперь можно смотреть исходники, в том виде, в котором их скачивает cargo!
crates.io: development update
Из заметного: на crates.io теперь можно смотреть исходники, в том виде, в котором их скачивает cargo!
blog.rust-lang.org
crates.io: development update | Rust Blog
Empowering everyone to build reliable and efficient software.
🔥12
Нє ну це база
😁19🔥9🤩1
Forwarded from Душный NLP
LLMs Develop Novel Social Biases Through Adaptive Exploration
Даже если полностью вычистить bias'ы из данных, модель в агентском цикле решение → фидбек вырастит новые с нуля. Даже о группах, которых не существует — из случайного шума. Чем новее модель, тем сильнее эффект, а промптом это не лечится, нужно менять целевую функцию.
Ребята из Принстонского университета привезли на ICML 2026 доклад, в котором утверждают, что вычищать существующие стереотипы из LLM недостаточно — модель успешно вырабатывает новые сама, в рантайме.
В подробностях разобрался наш коллега Александр Краснов.
#YaICML2026
Душный NLP
Даже если полностью вычистить bias'ы из данных, модель в агентском цикле решение → фидбек вырастит новые с нуля. Даже о группах, которых не существует — из случайного шума. Чем новее модель, тем сильнее эффект, а промптом это не лечится, нужно менять целевую функцию.
Ребята из Принстонского университета привезли на ICML 2026 доклад, в котором утверждают, что вычищать существующие стереотипы из LLM недостаточно — модель успешно вырабатывает новые сама, в рантайме.
В подробностях разобрался наш коллега Александр Краснов.
Сетап эксперимента из психологии: модель играет роль рекрутера и 40 раундов распределяет кандидатов из четырёх выдуманных этносов (Tufa, Aima, Reku, Weki) по профессиям. После каждого найма выносит вердикт: успех или провал.
Хитрость в том, что вероятность успеха у всех одинаковая — группы идентичны, и любые различия между ними модель может только выдумать. По сути, contextual bandit с шумным фидбеком.
Модель слишком мало исследует варианты и ранний случайный исход (например, «представитель Aima провалился на профессии учителя») закрепляется как впечатление обо всей группе, и к концу игры этносы разложены по своим профессиям. Вся история при этом есть в контексте, т.е. модель декларативно знает, что n=1 — не выборка, но действует при этом жадно.
По итогу эксперимента (стратификацию меряют через Stratification Index, т.е. насколько каждая группа загнана в узкий набор профессий):
• Все frontier-модели стратифицируют сильнее людей из оригинального эксперимента. У людей SI=0,84, у моделей в среднем 1,39, у o3 и Claude Sonnet — под 1,8.
• Чем новее модель, тем хуже дела: скор на классическом bias-бенчмарке BBQ обратно коррелирует с сегрегацией в итеративной игре. Сильный in-context learner увереннее делает вывод из трёх наблюдений, и эта уверенность подавляет исследование.
• В каждом прогоне bias'ы разные: паттерн рождается из шума внутри запуска, а не из претрейна. Single-turn-бенчмарки такое не ловят в принципе.
Промпт «будь справедливым» ничего не меняет. Работает только изменение самой цели. К успеху найма добавляют измеримый бонус за разнообразие, и стратификация падает ниже уровня людей и даже случайного распределения.
Хорошо, но как эта информация поможет обычному пользователю LLM?
На самом деле это касается не только «социальных» задач. Механизм срабатывает в любой длинной сессии, где модель принимает серию решений и видит исходы. Группой может быть что угодно. Агент один раз обжёгся на гипотезе «проблема в конфиге» и потом перестаёт рассматривать конфиг как класс причин. Вызов либы падает по случайной сетевой причине «библиотека не работает», дальше — костыли до конца сессии. И чем умнее модель, тем увереннее фиксация.
На практике абстрактное «будь объективным» не поможет, а сработает конкретика, встроенная в критерий успеха агента: «рассмотри минимум три гипотезы», «не отбрасывай вариант после одного провала», гейт в хуке, который не пропускает вывод без перепроверки альтернатив. По сути, мы вручную делаем исследование вариантов условием выигрыша (сам по себе агент не мотивирован). И если сессия накопила уверенные выводы из пары наблюдений, дешевле открыть свежий контекст, чем переубеждать залипшую модель.
Итого: bias — свойство не только данных, но и самого процесса принятия решений. Защищаться нужно на уровне целевой функции агента, а не датасета.
#YaICML2026
Душный NLP
❤7😁1