fortify жалуется на ресурс в блоке try-with-resources

У меня есть блок try-with-resources, который запускает несколько автоматически закрываемых объектов

    try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream("some-file), "UTF-8"))) {
         ......
    } catch (IOException e) {
        .....
    }

Fortify scan сообщает об этой проблеме

Функция ... in ... иногда не может освободить системный ресурс, выделенный FileInputStream () на линии ....

Мне интересно, что не так с приведенным выше кодом. Я думал, что try-with-resources может обрабатывать несколько автоматически закрываемых объектов. Есть идеи, в чем проблема? Спасибо.


person Jin    schedule 27.06.2018    source источник


Ответы (1)


Конечно, Fortify жалуется на то, чего не следует делать (ложные срабатывания), но приведенный выше код действительно может вызвать утечку объекта FileInputStream. Подумайте, что произойдет, если конструктор InputStreamReader выбрасывает исключение. В этом случае мы определенно создали FileInputStream, но он не будет очищен.

Кажется, у вас сложилось впечатление, что каждый объект, встречающийся в выражении, реализующем AutoCloseable, будет управляться оператором try-with-resources. Однако, если вы посмотрите на спецификацию языка: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

try ({VariableModifier} R Identifier = Expression ...)
    Block

переводится на:

{
    final {VariableModifierNoFinal} R Identifier = Expression;
    Throwable #primaryExc = null;
...

Таким образом, автоматически закрывается только «конечный результат» выражения (BufferedReader в вашем случае). (Обычно составные потоки / читатели / писатели распространяют операцию закрытия вниз по цепочке, но помните, что наша предпосылка заключается в том, что один из конструкторов отказал за исключением.)

Вы можете решить проблему с кодированием, объявив отдельные переменные для каждого элемента в цепочке:

        try (FileInputStream fis = new FileInputStream("some-file");
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            BufferedReader bufferedReader = new BufferedReader(isr)) {
            //...
        }

Более или менее этот же пример находится на странице Повышение безопасности проблемы Не выпущено поток ресурсов для try-with-resource.

person Jeremy K    schedule 17.06.2020