Nous utilisons des cookies pour améliorer votre expérience de navigation. En savoir plus
Accepter
to the top
close form

Remplissez le formulaire ci‑dessous en 2 étapes simples :

Vos coordonnées :

Étape 1
Félicitations ! Voici votre code promo !

Type de licence souhaité :

Étape 2
Team license
Enterprise licence
** En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité
close form
Demandez des tarifs
Nouvelle licence
Renouvellement de licence
--Sélectionnez la devise--
USD
EUR
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
La licence PVS‑Studio gratuit pour les spécialistes Microsoft MVP
close form
Pour obtenir la licence de votre projet open source, s’il vous plait rempliez ce formulaire
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
I am interested to try it on the platforms:
* En cliquant sur ce bouton, vous déclarez accepter notre politique de confidentialité

close form
check circle
Votre message a été envoyé.

Nous vous répondrons à


Si vous n'avez toujours pas reçu de réponse, vérifiez votre dossier
Spam/Junk et cliquez sur le bouton "Not Spam".
De cette façon, vous ne manquerez la réponse de notre équipe.

>
>
>
V1090. The 'std::uncaught_exception' fu…
menu mobile close menu
Analyzer diagnostics
General Analysis (C++)
General Analysis (C#)
General Analysis (Java)
Micro-Optimizations (C++)
Diagnosis of 64-bit errors (Viva64, C++)
Customer specific requests (C++)
MISRA errors
AUTOSAR errors
OWASP errors (C#)
Problems related to code analyzer
Additional information
toggle menu Contents

V1090. The 'std::uncaught_exception' function is deprecated since C++17 and is removed in C++20. Consider replacing this function with 'std::uncaught_exceptions'.

07 Sep 2022

The analyzer detected the 'std::uncaught_exception' function call. The use of this function may lead to incorrect program logic. Since C++17, this function has been deprecated and should be replaced with the 'std::uncaught_exceptions' function.

The 'std::uncaught_exception' function is usually used to understand whether the code is called when the stack unwinding takes place. Let's look at the following example:

constexpr std::string_view defaultSymlinkPath = "system/logs/log.txt";

class Logger
{
  std::string   m_fileName;
  std::ofstream m_fileStream;

  Logger(const char *filename)
    : m_fileName { filename }
    , m_fileStream { m_fileName }
  {
  }

  void Log(std::string_view);

  ~Logger()
  {
    fileStream.close();
    if (!std::uncaught_exception())
    {
      std::filesystem::create_symlink(m_fileName, defaultSymlinkPath);
    }
  }
};

class Calculator
{
public:
  int64_t Calc(const std::vector<std::string> &params);
  // ....
  ~Calculator()
  {
    try
    {
      Logger logger("log.txt");
      Logger.Log("Calculator destroyed");
    }
    catch (...)
    {
      // ....
    }
  }
}

int64_t Process(const std::vector<std::string> &params)
{
  try
  {
    Calculator calculator;
    return Calculator.Calc(params);
  }
  catch (...)
  {
    // ....
  }
}

Inside the 'Logger' class destructor, the 'std::filesystem::create_symlink' function is called. This function may throw an exception, for example, if a program doesn't have permissions to use the 'system/logs/log.txt' path. If the 'Logger' destructor is called directly as a result of the stack unwinding, then, it is impossible to throw exceptions from this destructor — the program will be aborted via 'std::terminate'. Therefore, before the function is called, a developer makes an extra check - 'if (!std::uncaught_exception())'.

However, such code contains an error. Suppose the 'Calc' function throws an exception. Then, before the catch-clause is executed, the 'Calculator' destructor will be called. An instance of the 'Logger' class will be created inside this call, and the message will be written to the log. After that, the 'Logger' destructor will be called. Then, the 'std::uncaught_exception' function will be called inside the destructor. This function will return 'true' because the exception thrown by the 'Calc' function has not been caught yet. Therefore, a symbolic link to the log file will not be created.

However, in this case, you can try to create the symbolic link. The fact is that the 'Logger' destructor will not be called directly as a result of the stack unwinding — it will be called from the 'Calculator' destructor. Therefore, you can throw an exception from the 'Logger' destructor — you only need to catch this exception before it exits from the 'Calculator' destructor.

To fix this, you need to use the 'std::uncaught_exceptions' function from C++17:

class Logger
{
  std::string   m_fileName;
  std::ofstream m_fileStream;
  int           m_exceptions = std::uncaught_exceptions(); // <=

  Logger(const char *filename)
    : m_fileName { filename }
    , m_fileStream { m_fileName }
  {
  }

  ~Logger()
  {
    fileStream.close();
    if (m_exceptions == std::uncaught_exceptions())
    {
      std::filesystem::create_symlink(m_fileName, defaultSymlinkPath);
    }
  }
};

Now, when you create the 'Logger' instance, the current number of uncaught exceptions will be saved in the 'm_exceptions' field. If no new exceptions were thrown between creating the object and calling its destructor, the condition will be true. Therefore, the program will try to create the symbolic link to the log file. If an exception is thrown, it will be caught and processed in the 'Calculator' destructor, and the program will continue execution.

This diagnostic is classified as: