Статьи

Использование FindBugs для создания значительно меньшего количества ошибочного кода

Некоторое время назад пользователь Java-монитора, форум нашего партнера по JCG , Киса Яна , заметил, что его система форсирует большое количество полных сборок мусора, несмотря на то, что общее использование памяти было низким. Приблизительная оценка причины проблемы предполагала возможный вызов System.gc (), выполняемый одной из используемых библиотек. Давайте посмотрим, что скажет наш партнер об устранении подобных проблем, чтобы создать значительно менее ошибочный код.

… Мне пришло в голову, что есть инструмент, который мог бы помочь с проблемой System.gc () . Он удачно называется FindBugs . На самом деле их несколько ( PMD и CheckStyle — другие, похожие инструменты), но FindBugs хорош, потому что вам на самом деле не нужен исходный код приложения для проверки на наличие ошибок. Все, что вам нужно, это файлы JAR и / или файлы классов. Еще одна замечательная особенность заключается в том, что каждый отчет очень хорошо документирован. Вы не просто получаете смутные предупреждения, от которых вы отказываетесь через несколько минут, но вы можете найти объяснение для каждого предупреждения в режиме онлайн .

Вот пример вывода FindBugs , когда вы запускаете его для зонда Java-монитора .

01
02
03
04
05
06
07
08
09
10
11
12
$ findbugs -textui -effort:max java-monitor-probes/build/WEB-INF/classes
The following classes needed for analysis were missing:
  javax.servlet.http.HttpServlet
  javax.servlet.Filter
  javax.servlet.http.HttpServletResponse
  javax.servlet.ServletException
  javax.servlet.ServletConfig
  javax.servlet.FilterConfig
  javax.servlet.ServletRequest
  javax.servlet.ServletResponse
  javax.servlet.FilterChain
Missing classes: 7

Из этого отчета вы можете видеть, что FindBugs не может найти никаких проблем с самим кодом. Есть несколько классов, от которых зависит код. Они не были включены в анализ. Поскольку это все классы, предоставляемые Sun, я предполагаю, что они не содержат ошибок. *кашель*

Так или иначе. Давайте сделаем анализ немного более сочным. Вот вывод при запуске FindBugs против известного драйвера MySQL JDBC. Я уверен, что многие из вас сегодня используют его в производстве. Этот код дает значительно больше результатов, и FindBugs занимает некоторое время для анализа всего пакета. Я показал только несколько строк из 154 предупреждений.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
$ findbugs -textui -effort:max mysql-connector-java-5.1.5-bin.jar
  ......
H C NP: Method call in com.mysql.jdbc.profiler.ProfilerEvent.pack() passes null for unconditionally dereferenced parameter of writeBytes(byte[], byte[], int)  Method invoked at ProfilerEvent.java:[line 375]
  ......
M D NP: Possible null pointer dereference of s1 on path that might be infeasible in com.mysql.jdbc.ConnectionImpl.nullSafeCompare(String, String)  Dereferenced at ConnectionImpl.java:[line 341]
  ......
M C NP: Method call in com.mysql.jdbc.DatabaseMetaData.getInstance(ConnectionImpl, String) passes null for unconditionally dereferenced parameter of new DatabaseMetaData(ConnectionImpl, String)  Method invoked at DatabaseMetaData.java:[line 632]
  ......
H S SQL: Method com.mysql.jdbc.DatabaseMetaData.getColumnPrivileges(String, String, String, String) passes a nonconstant String to an execute method on an SQL statement  At DatabaseMetaData.java:[line 2156]
H S SQL: Method com.mysql.jdbc.DatabaseMetaData.getTablePrivileges(String, String, String) passes a nonconstant String to an execute method on an SQL statement  At DatabaseMetaData.java:[line 4638]
M S SQL: Method com.mysql.jdbc.ConnectionImpl.setSessionVariables() passes a nonconstant String to an execute method on an SQL statement  At ConnectionImpl.java:[line 5074]
  ......
M M IS: Inconsistent synchronization of com.mysql.jdbc.CallableStatement.outputParameterResults; locked 50% of time  Unsynchronized access at CallableStatement.java:[line 1948]
M M IS: Inconsistent synchronization of com.mysql.jdbc.StatementImpl.wasCancelledByTimeout; locked 83% of time  Unsynchronized access at PreparedStatement.java:[line 1756]
  ......
Warnings generated: 154
  ......

Научиться читать вывод FindBugs занимает немного времени. Что я делаю, так это просто прорабатываю определенную ошибку или предупреждение, когда мне надоедает или разочаровывается код, который я должен писать. Это моя прокрастинация. 🙂

Я выбрал только то, что мне как разработчику кажется проблематичным: «пропускает ноль для безусловного разыменованного параметра». Ик. NullPointerException кто-нибудь? Конечно, это может быть тестовый код или даже неиспользуемый код, который все еще находится в стадии разработки. Как насчет этого: «передает непостоянную строку в метод execute для оператора SQL». Хм. Если этот флажок не установлен, это может быть причиной уязвимости SQL-инъекций.

Ранее я говорил, что FindBugs не требует от вас доступа к исходному коду приложения для поиска ошибок в нем. Просто для смеха, давайте посмотрим на один из краеугольных камней наших серверов приложений Java EE: драйвер Oracle JDBC.

01
02
03
04
05
06
07
08
09
10
11
12
13
$ findbugs -textui -effort:max ojdbc6.jar
  ......
M B Dm: oracle.sql.ConverterArchive.openArchiveforRead() invokes System.exit(...), which shuts down the entire virtual machine  At ConverterArchive.java:[line 375]
M B Dm: oracle.sql.ConverterArchive.closeArchiveforRead() invokes System.exit(...), which shuts down the entire virtual machine  At ConverterArchive.java:[line 390]
  ......
M B ES: Comparison of String objects using == or != in oracle.jdbc.connector.OracleConnectionRequestInfo.equals(Object)   At OracleConnectionRequestInfo.java:[line 104]
  ......
H C IL: There is an apparent infinite recursive loop in oracle.jdbc.rowset.OracleCachedRowSet.updateBlob(int, InputStream, long)  At OracleCachedRowSet.java:[line 6365]
H C IL: There is an apparent infinite recursive loop in oracle.jdbc.rowset.OracleCachedRowSet.updateClob(int, Reader, long)  At OracleCachedRowSet.java:[line 6445]
H C IL: There is an apparent infinite recursive loop in oracle.jdbc.rowset.OracleCachedRowSet.updateNClob(int, Reader, long)  At OracleCachedRowSet.java:[line 6535]
  ......
Warnings generated: 1028
  ......

Этот водитель выдает не менее 1028 предупреждений. Ух ты. Я не утверждаю, что драйвер Oracle JDBC на самом деле является плохим фрагментом кода. Я просто нахожу, что это пахнет немного . 🙂 Разработчики Oracle, возможно, захотят иметь дело с устранением предупреждений о сообщении findbugs. Там есть много небольших предложений по производительности и стабильности.

И да: findbugs проверяет использование System.gc () .

PS. Пожалуйста, имейте в виду, что я использовал FindBugs 1.3.7. В этой версии FindBugs есть ошибка, из-за которой он генерирует ложные срабатывания для очистки ресурсов базы данных .

PPS. Кого я шучу: я думаю, что драйвер Oracle плох. Бесконечные циклы? System.exit ()? Пожалуйста.

Всегда помогайте… нуждающемуся кодеру 😉

Byron

Статьи по Теме: