Уязвимость SonarQube: явно объявлять видимость для переменной

Я знаю, что это уже давно, но теперь я чувствую, что мы имеем дело с C ++ 11-17, кто-то должен упоминать лямбда. Если вы запишете это в лямбду, которая будет вызываться асинхронно в более поздний момент времени, возможно, что ваш «этот» объект будет уничтожен до того, как эта лямбда будет вызвана.

, т.е. передавая ее как callback к некоторой дорогостоящей функции, которая запускается из отдельного потока или просто асинхронно вообще

EDIT: для того, чтобы быть понятным, вопрос: «Имеет ли смысл проверять, является ли это нулевым» I просто предлагаю сценарий, где это имеет смысл, который может стать более распространенным с более широким использованием современного C ++.

Продуманный пример: этот код полностью работоспособен. Чтобы увидеть небезопасное поведение, просто закомментируйте вызов безопасного поведения и раскомментируйте небезопасный позывной.

#include <memory>
#include <functional>
#include <iostream>
#include <future>

class SomeAPI
{
public:
    SomeAPI() = default;

    void DoWork(std::function<void(int)> cb)
    {
        DoAsync(cb);
    }

private:
    void DoAsync(std::function<void(int)> cb)
    {
        std::cout << "SomeAPI about to do async work\n";
        m_future = std::async(std::launch::async, [](auto cb)
        {
            std::cout << "Async thread sleeping 10 seconds (Doing work).\n";
            std::this_thread::sleep_for(std::chrono::seconds{ 10 });
            // Do a bunch of work and set a status indicating success or failure.
            // Assume 0 is success.
            int status = 0;
            std::cout << "Executing callback.\n";
            cb(status);
            std::cout << "Callback Executed.\n";
        }, cb);
    };
    std::future<void> m_future;
};

class SomeOtherClass
{
public:
    void SetSuccess(int success) { m_success = success; }
private:
    bool m_success = false;
};
class SomeClass : public std::enable_shared_from_this<SomeClass>
{
public:
    SomeClass(SomeAPI* api)
        : m_api(api)
    {
    }

    void DoWorkUnsafe()
    {
        std::cout << "DoWorkUnsafe about to pass callback to async executer.\n";
        // Call DoWork on the API.
        // DoWork takes some time.
        // When DoWork is finished, it calls the callback that we sent in.
        m_api->DoWork([this](int status)
        {
            // Undefined behavior
            m_value = 17;
            // Crash
            m_data->SetSuccess(true);
            ReportSuccess();
        });
    }

    void DoWorkSafe()
    {
        // Create a weak point from a shared pointer to this.
        std::weak_ptr<SomeClass> this_ = shared_from_this();
        std::cout << "DoWorkSafe about to pass callback to async executer.\n";
        // Capture the weak pointer.
        m_api->DoWork([this_](int status)
        {
            // Test the weak pointer.
            if (auto sp = this_.lock())
            {
                std::cout << "Async work finished.\n";
                // If its good, then we are still alive and safe to execute on this.
                sp->m_value = 17;
                sp->m_data->SetSuccess(true);
                sp->ReportSuccess();
            }
        });
    }
private:
    void ReportSuccess()
    {
        // Tell everyone who cares that a thing has succeeded.
    };

    SomeAPI* m_api;
    std::shared_ptr<SomeOtherClass> m_data = std::shared_ptr<SomeOtherClass>();
    int m_value;
};

int main()
{
    std::shared_ptr<SomeAPI> api = std::make_shared<SomeAPI>();
    std::shared_ptr<SomeClass> someClass = std::make_shared<SomeClass>(api.get());

    someClass->DoWorkSafe();

    // Comment out the above line and uncomment the below line
    // to see the unsafe behavior.
    //someClass->DoWorkUnsafe();

    std::cout << "Deleting someClass\n";
    someClass.reset();

    std::cout << "Main thread sleeping for 20 seconds.\n";
    std::this_thread::sleep_for(std::chrono::seconds{ 20 });

    return 0;
}
2
задан Valeriy K. 1 March 2019 в 07:27
поделиться

1 ответ

Взгляните на описание правила .

Если явно не объявить видимость переменной-члена, это может привести к тому, что вы будете иметь видимость, которую вы не ожидаете, и потенциально оставить ее открытой для неожиданного изменения другими классами.

Если у вас есть свойство пакета класса private, тогда любой класс в этом же пакете может изменить это свойство.

Но у пакета Private все еще есть действительное использование. Например, вы можете объявить класс как частный пакет, чтобы его можно было использовать внутри пакета, в котором он объявлен, но остается скрытым от публичного использования.

0
ответ дан Januson 1 March 2019 в 07:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: