>
>
>
Эксперимент по поиску ошибок в коде C# …

Сергей Хренов
Статей: 39

Эксперимент по поиску ошибок в коде C# компонентов Tizen

Недавно ко мне обратился мой коллега, Андрей Карпов, с просьбой попробовать найти 3-4 ошибки в коде компонентов Tizen на языке C#. Сам он не так давно занимался анализом Tizen на предмет поиска ошибок в C/C++ коде и сейчас пишет несколько статей на эту тему. Вдохновлённый его примером, я провёл эксперимент по поиску ошибок в C# компонентах Tizen. Сразу скажу, что эксперимент прошел удачно, и в дальнейшем я займусь написанием большой статьи на эту тему, а сейчас просто поделюсь результатами пробной проверки.

Для начала я не стал проводить глубокий анализ всей базы исходного кода Tizen, а выбрал пару проектов на языке C#, проверка которых не потребовала бы особых усилий. Цель нашего эксперимента – постараться понять, нужно ли работать в этом направлении.

В результате даже такой поверхностной проверки мне довольно быстро удалось найти несколько реальных ошибок, что позволяет утверждать: здесь есть работа для C# анализатора PVS-Studio. В данной короткой заметке я ограничусь описанием этих ошибок, оставив более подробное изучение данного вопроса на будущее.

По моим подсчётам, код Tizen содержит 4 929 файлов исходного кода с расширением cs, в которых имеется около 691 000 строк кода. Исходный код довольно объёмен и его полноценный анализ потребует некоторого времени. Позже, по результатам этой работы, я напишу развёрнутую статью.

Пока же приведу описание трёх из списка найденных мною на данном этапе работы ошибок. Для простоты я буду указывать имя папки верхнего уровня в иерархии проектов Tizen, где содержался файл с ошибкой.

xamarin-forms-tizen

PVS-Studio: V3001 There are identical sub-expressions 'RwWait' to the left and to the right of the '|' operator. Xamarin.Forms.Platform.WP8 SplitOrderedList.cs 458

struct SimpleRwLock
{
  const int RwWait = 1;
  const int RwWrite = 2;
  const int RwRead = 4;
  ....
  public void EnterReadLock()
  {
    var sw = new SpinWait();
    do
    {
      while ((_rwlock & (RwWrite | RwWait)) > 0)
        sw.SpinOnce();

      if ((Interlocked.Add(ref _rwlock, RwRead)
          & (RwWait | RwWait)) == 0)                // <=
        return;

      Interlocked.Add(ref _rwlock, -RwRead);
    } while (true);
  }
  ....
}

Вероятно, в условии блока if допущена опечатка, связанная с похожестью имен констант RwWait и RwWrite, в результате чего константа RwWait была ошибочно использована дважды. В пользу этого говорит и условие в блоке while выше, где используется правильное сочетание RwWrite | RwWait.

PVS-Studio: V3095 The 'type' object was used before it was verified against null. Check lines: 147, 149. Xamarin.Forms.Xaml ExpandMarkupsVisitor.cs 147

CWE-476 NULL Pointer Dereference

public class MarkupExpansionParser : 
  MarkupExpressionParser, IExpressionParser<INode>
{
  ....
  public INode Parse(....)
  {
    ....
    Type type;
    ....
    var xmltype = new XmlType(namespaceuri, type.Name, null); // <=
   
    if (type == null)
      throw new NotSupportedException();
    ....
  }
  ....
}

Переменную type сначала используют для доступа к type.Name, а уже затем проверяют на равенство null. В результате возможно возникновение исключения типа NullReferenceException.

csapi-location

PVS-Studio. V3110 Possible infinite recursion inside 'Timestamp' property. Tizen.Location Location.cs 186

CWE-674 Uncontrolled Recursion

public class Location
{
  ....
  internal int _timestamp;
  ....
  public DateTime Timestamp
  {
    get
    {
        return Interop.ConvertDateTime(_timestamp);
    }
    internal set
    {
        Timestamp = value;             // <=
    }
  }  
  ....
}

Данный фрагмент кода содержит ошибку, неизбежно приводящую к исчерпанию стека (бесконечная рекурсия) при попытке доступа на запись к свойству Timestamp. При этом нет видимых признаков опечатки. Поле _timestamp значительно отличается по написанию от Timestamp, так что непохоже, что их могли перепутать. К тому же, _timestamp имеет тип int, что делает невозможным прямое присвоение ему значения value типа DateTime. Потребовалось бы преобразование типа, наподобие того, что реализовано в секции get. Думаю, исправить данную ошибку смог бы только автор.

Думаю, для начала достаточно, остальные ошибки, найденные на этом этапе, я приберегу для следующей статьи.

Можно сделать вывод, что анализатор PVS-Studio может быть использован не только для проверки C и C++ кода, но и для проверки компонентов, разработанных на C#.

Скачать и попробовать PVS-Studio: http://www.viva64.com/ru/pvs-studio/

Дополнительные ссылки: