C# программист, испытай себя — найди ошибку
Анализатор PVS-Studio регулярно пополняется новыми диагностическими правилами. Что интересно, часто диагностики обнаруживают подозрительные фрагменты кода еще до окончания всех работ. Например, в процессе тестирования на open-source проектах. Одной из подобных интересных 'находок' и хотелось бы поделиться сегодня с вами.
Как говорилось выше, один из этапов тестирования диагностического правила — проверка его работы на реальной кодовой базе. Для этого используется набор отобранных open-source проектов, для которых проводится анализ. Очевидное преимущество такого подхода — возможность посмотреть, как ведёт себя диагностическое правило в «реальных условиях». Менее очевидное — иногда находится что-то настолько интересное, что про это и заметку не грех написать.
Итак, предлагаю посмотреть на код из проекта Bouncy Castle C# и найти в нём ошибку:
public static string ToString(object[] a)
{
StringBuilder sb = new StringBuilder('[');
if (a.Length > 0)
{
sb.Append(a[0]);
for (int index = 1; index < a.Length; ++index)
{
sb.Append(", ").Append(a[index]);
}
}
sb.Append(']');
return sb.ToString();
}
Для тех, кто любит подглядывать, я добавил картинку, чтобы сохранить интригу.
Уверен, многие не смогли найти ошибку без открытия IDE или документации к классу StringBuilder. Ошибка допущена при вызове конструктора:
StringBuilder sb = new StringBuilder('[');
Собственно, об этом и предупреждает статический анализатор PVS-Studio: V3165 Character literal '[' is passed as an argument of the 'Int32' type whereas similar overload with the string parameter exists. Perhaps, a string literal should be used instead. Arrays.cs 193.
Программист хотел создать экземпляр типа StringBuilder, строка в котором будет начинаться с символа '['. Однако из-за опечатки будет получен объект ёмкостью под 91 элемент, не содержащий символов.
Это произошло из-за того, что вместо двойных кавычек использовались одинарные, что привело к вызову не той перегрузки конструктора:
....
public StringBuilder(int capacity);
public StringBuilder(string? value);
....
При вызове конструктора символьный литерал '[' будет неявно приведен к соответствующему значению типа int (91 в Unicode). Это приведет к вызову конструктора с параметром типа int, задающим начальную вместимость. Программист же хотел вызвать конструктор, задающий начало строки.
Для исправления ошибки следует заменить символьный литерал на строковый (т.е. использовать »[», а не '['), что позволит вызвать правильную перегрузку конструктора.
Мы решили не ограничиваться этим паттерном и расширили случаи, которые рассматривает диагностика. В результате, кроме символьных литералов, сейчас рассматриваются и другие выражения типа char, а также, аналогично конструкторам, проверяются методы.
Диагностика, срабатывание которой было описано выше, была добавлена в релизе PVS-Studio 7.11. Вы сами можете загрузить последнюю версию анализатора и посмотреть на что способна не только диагностика V3165, но и другие диагностики для языков C, C++, C# и Java.
Кстати, идеи диагностик нам часто предлагают сами пользователи. Так получилось и в этот раз — спасибо пользователю Krypt с ресурса Habr. Если у вас также есть идеи диагностических правил — не стесняйтесь предлагать их!
P.S. В текущей кодовой базе проекта данная ошибка уже исправлена. Однако это не отменяет того факта, что какое-то время она существовала в коде, и что статический анализ позволяет выявлять подобные проблемы и исправлять их на самых ранних этапах.
Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Valery Komarov. C# Programmer, It’s Time to Test Yourself and Find Error.