michaellukashov / Far-NetBox

SFTP/SCP/FTP/FTPS/WebDAV/S3 client for Far Manager 3 (http://farmanager.com/)
https://forum.farmanager.com/viewtopic.php?t=6317
GNU General Public License v2.0
156 stars 52 forks source link

Проблема с try__finally #362

Closed ssvine closed 5 months ago

ssvine commented 5 months ago

Встретился с ошибкой, когда подключался к сбойному серверу по WebDAVFar взял и неожиданно закрылся без каких-либо сообщений.

Небольшое расследование показало, что это произошло из-за вызова std::terminate() по причине того, что брошенное исключение осталось необработанным. Это произошло здесь:

void TTerminal::DoStartup()
{
  // ...
  try__finally
  {
    // ...
  }
  __finally
  {
    DoEndTransaction(true);  // отсюда пришло исключение
  } end_try__finally
  // ...
}

Исключение из DoEndTransaction(true) было выкинуто примерно по такой цепочке:

С первого взгляда ничего криминального — по идее брошенное исключение должно быть обработано выше в функции TTerminal::InternalTryOpen, но этого не произошло.

Оказалось, что блок __finally реализован как вызов деструктора, который по умолчанию имеет спецификатор noexcept.

Возможные варианты решения:

  1. Добавить спецификатор noexcept(false) в деструктор
  2. Переписать с использованием SCOPE_EXIT, у которого деструктор уже имеет спецификатор noexcept(false)

Честно говоря, я не знаю сколько ещё блоков __finally содержат в себе функции, которые могут бросать исключения, поэтому проще выглядит вариант 1. Да и вообще логично, что __finally отдаёт исключения наружу для дальнейшей обработки.

ssvine commented 5 months ago

Спасибо, теперь всё ок

michaellukashov commented 5 months ago

Переделал make_try_finally чтобы исправить предупреждение SonarCloud. Проверьте пожалуйста, не возникает ли снова выявленная проблема

ssvine commented 5 months ago

Проверил - всё отлично