2016-08-31 10 views
1

Мы разрабатываем статический инструмент анализа кода, который направлен на улучшение кода с помощью некоторых подсказок.Как найти потенциальные точки исключения NullReferenceException в утилите анализатора статического кода?

Мы хотим найти места, где разработчик забыл проверить недействительность переменной или свойства или метода return и получил доступ к элементам через Dot Notation, поскольку он может столкнуться с NullReferenceException.

Например, этот код:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var human = new Human(); 
     if (human.Name.Length > 10) 
     { 
      // Jeez! you have a long name; 
     } 
    } 
} 

public class Human 
{ 
    public string Name { get; set; } 
} 

Мы используем Mono.Cecil и мы находим тело всех методов всех типов в данной сборке, и для каждого тела метода мы находим Инструкцию о нем, и то мы проверяем операции Callvirt. Тем не менее, что не поддерживает этот пример:

class Program 
{ 
    static string name; 

    static void Main(string[] args) 
    { 
     if (name.Length > 10) 
     { 
     } 
    } 
} 

Как мы можем найти все доступы к членам (переменный, поле, свойство, метод) данный обнуляемого типа?

Update: На самом деле мы ищем Opcodes, которые представляют доступ члена для данной переменной в IL. Это возможно?

+0

Вы хотите создать инструмент, который выполняет статический анализ кода с использованием отражения, * который не является небольшим подвигом *, но имеет основной вопрос о том, как использовать отражение? Я думаю, вы ставите телегу перед лошадью на этом. Я рекомендую вам сначала узнать все о рефлексии. Затем вам нужно будет узнать, как разрушить метод, чтобы ваш код мог находить случаи, подобные приведенным выше (это более сложная часть). О да, и после этого вам придется как-то уведомить пользователя (не уверен, что это встроенный или через консольный вывод). Кстати, есть инструменты, которые уже много делают. – Igor

+0

Инструмент, такой как https://www.jetbrains.com/resharper, даст вам знать (inline), если есть возможность исключения NullReferenceException, среди прочего. –

+0

@Igor Мы уже разработали анализ/качество кода на основе * TFS * с использованием * Политики регистрации *. В настоящее время он проверяет более 180 правил, которые мы определили, чтобы улучшить качество множества огромных кодовых баз, которые разрабатываются примерно 15 разработчиками. Этот вопрос касается нового правила, которое мы хотим добавить: проверка Null должна быть там, где требуется, для предотвращения исключения NullReferenceException. –

ответ

2

Документация NullReferenceException услужливо документы следующие:

Следующий Microsoft Intermediate Language (MSIL) инструкции бросить NullReferenceException: callvirt, cpblk, cpobj, initblk, ldelem.<type>, ldelema, ldfld, ldflda, ldind.<type>, ldlen, stelem.<type>, stfld, , throw, и unbox.

Они ломаются на следующее: доступ

  • массива: ldelem, ldelema, ldlen, stelem. Ссылка на массив не должна быть null.
  • Доступ к номерам без доступа к элементам: ldfld, ldflda, stfld. Ссылка на объект не должна быть null.
  • Способ доступа: callvirt. Ссылка на объект не должна быть null. Доступ к свойствам - это также доступ к методам, поскольку он вызывает свойство getter/setter.
  • Указатель/справочный доступ: cpblk, cpobj, initblk, ldind, stind. Указатель/ссылка не должна быть null. В проверенном управляемом коде эти коды операций обычно не используются в контексте, где их аргументы могут быть null.
  • Бросание исключения: throw. Ссылка на исключение не должна быть null.
  • Unboxing: unbox.Ссылка на объект не должна быть null.

Отслеживание аргументов opcode обратно к переменным/полям - это еще один вопрос. Это может быть произвольно сложным, поскольку коды операций заботятся только о том, что находится в стеке, а не о том, откуда оно взялось. В некоторых случаях вы можете иметь дело с выражениями (a[0].SomeMethod().FieldAccess, где любой из a, a[0] и a[0].SomeMethod() может быть null, когда они не должны быть).

Вам лучше не проверять это на уровне IL, но используя Roslyn, чтобы предоставить вам анализ на уровне языка. Получение высококачественной обратной связи намного проще с доступом к источнику.

Даже тогда имейте в виду, что высококачественный статический анализ для устранения неполадок нелегкий. Вы можете, конечно, написать анализатор, который будет с радостью предупреждать о каждом возможном случае, когда программист может забыл проверить, но такой анализатор становится почти бесполезным, если программист вынужден вставлять тонны лишних проверок для ссылок, которые являются , очевидно никогда null. Если вы привяжете это к политике регистрации TFS, будьте готовы получить угрозы смерти от разработчиков и менеджеров, которые хотят знать, почему производительность снижается.

Существует причина, по которой существующие инструменты, такие как Resharper, добавляют много attributes для управления анализом, и есть proposal, чтобы добавить проверку на соответствие null на C#. Знайте, что вы получаете, прежде чем изобретать колесо.