首页
社区
课程
招聘
[原创]C++ static关键字引发的思考
发表于: 2023-12-9 20:57 10921

[原创]C++ static关键字引发的思考

2023-12-9 20:57
10921

在类中,可以使用static关键字修饰成员函数和变量,被修饰后的函数或变量被称为静态成员函数或变量。它们属于整个类,不属于某一个对象,这意味着无需创建对象即可访问静态成员函数或变量。最常见的一个用法就是单例模式(整个类仅可只有一个对象),例:

此处的static主要用于限制修饰对象的作用域。

面向过程中的静态局部变量"只能被初始化一次"是如何实现的?
考虑到静态变量有可能被多次初始化且使用变量初始化,使用的例子如下:

func_a函数中是以常量初始化静态局部变量func_a_value,因此编译器直接将0x1234写入.data对应的位置,这与单(多)线程无关,与单(多)次初始化无关。
00
若函数以变量形式初始化静态局部变量,则实现初始化一次的原理见静态局部变量res

存在多个线程初始化res的情况,因此需要进行线程同步。IDA反汇编func_b函数之后的结果如下:
01
对应的C++代码如下:

_Init_thread_header的源代码如下:

_Init_thread_footer的源代码如下:

从上述代码来看,事情非常明了。pOnce指向的内存初始值为0,通过临界区来实现线程同步,同时只能有一个线程进入到_Init_thread_header和_Init_thread_footer函数。

因为线程是乱序执行的,所以res的结果不是确定的,如下图:
02
02

源码的编译环境是Ubuntu 22.04,g++ 11.4.0

同Windows下的常量赋值给静态局部变量,IDA的视图如下:
04
变量赋值给静态局部变量见"静态局部变量res"章节

IDA反汇编func_b的结果如下:
05
从该图中可以看出,__cxa_guard_acquire发挥同_Init_thread_header相同的效果,而__cxa_guard_release发挥同_Init_thread_footer相同的效果。这两个函数的源码如下:
__cxa_guard_acquire函数源码

__cxa_guard_release函数源码

像Windows MSVC平台那样分CASE分析,初始状态*g = 0,__gnu_cxx::__is_single_threaded() = true。__gnu_cxx::__is_single_threaded()在pthread_create函数已经被设置为了false,这个操作在执行func_b函数之前。

class Singleton
{
public:
    static Singleton& instance() // 静态方法
    {
        static Singleton inst;  // 静态对象在instance中声明
        return inst;
    }
    int& get() { return value_; }
private:
    Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; }
private:
    int value_;                 // 非静态成员变量
};
 
int value = Singleton::instance().get() // Singleton::instance()返回静态对象inst
class Singleton
{
public:
    static Singleton& instance() // 静态方法
    {
        static Singleton inst;  // 静态对象在instance中声明
        return inst;
    }
    int& get() { return value_; }
private:
    Singleton() : value_(0) { std::cout << "Singleton::Singleton()" << std::endl; }
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
    ~Singleton() { std::cout << "Singleton::~Singleton()" << std::endl; }
private:
    int value_;                 // 非静态成员变量
};
 
int value = Singleton::instance().get() // Singleton::instance()返回静态对象inst
#include <iostream>
#include <thread>
#include <chrono>         // std::chrono::seconds
 
using namespace std;
 
void func_a();
void func_b(int a, int b);
 
int main()
{
    func_a();
    thread t1(func_b, 1, 2);
    thread t2(func_b, 3, 4);
    thread t3(func_b, 5, 6);
    thread t4(func_b, 7, 8);
 
    std::this_thread::sleep_for(std::chrono::seconds(1));
    getchar();
    t1.join();t2.join();t3.join();t4.join();
    return 0;
}
 
void func_a()
{
    static int func_a_value = 0x1234;
    cout << "func_a_value => " << func_a_value << ", current function = > " << __FUNCTION__ << endl;
}
 
void func_b(int a, int b)
{
    static int res = a + b;
    cout << "res => " << res << ", current thread id => " << std::this_thread::get_id() << endl;
}
#include <iostream>
#include <thread>
#include <chrono>         // std::chrono::seconds
 
using namespace std;
 
void func_a();
void func_b(int a, int b);
 
int main()
{
    func_a();
    thread t1(func_b, 1, 2);
    thread t2(func_b, 3, 4);
    thread t3(func_b, 5, 6);
    thread t4(func_b, 7, 8);
 
    std::this_thread::sleep_for(std::chrono::seconds(1));
    getchar();
    t1.join();t2.join();t3.join();t4.join();
    return 0;
}
 
void func_a()
{
    static int func_a_value = 0x1234;
    cout << "func_a_value => " << func_a_value << ", current function = > " << __FUNCTION__ << endl;
}
 
void func_b(int a, int b)
{
    static int res = a + b;
    cout << "res => " << res << ", current thread id => " << std::this_thread::get_id() << endl;
}
if(pOnce > *(int *)(NtCurrentTeb()->ThreadLocalStoragePointer[0] + 0x104)  // tls中存储的全局 局部静态变量初始化计数器, 初始值为INT_MIN(0x80000000)
{
    _Init_thread_header(&pOnce)
    if ( pOnce == -1 )
    {
      res = b + a;    // 初始化代码
      _Init_thread_footer(&pOnce);
    }
}
if(pOnce > *(int *)(NtCurrentTeb()->ThreadLocalStoragePointer[0] + 0x104)  // tls中存储的全局 局部静态变量初始化计数器, 初始值为INT_MIN(0x80000000)
{
    _Init_thread_header(&pOnce)
    if ( pOnce == -1 )
    {
      res = b + a;    // 初始化代码
      _Init_thread_footer(&pOnce);
    }
}
// 代码所在的文件为thread_safe_statics.cpp
extern "C" void __cdecl _Init_thread_header(int* const pOnce) noexcept
{
    _Init_thread_lock();                // 进入临界区
 
    if (*pOnce == uninitialized)        // uninitialized = 0
    {
        *pOnce = being_initialized;     // being_initialized = -1
    }
    else
    {
        while (*pOnce == being_initialized)
        {
            // Timeout can be replaced with an infinite wait when XP support is
            // removed or the XP-based condition variable is sophisticated enough
            // to guarantee all waiting threads will be woken when the variable is
            // signalled.
            _Init_thread_wait(xp_timeout);
 
            if (*pOnce == uninitialized)
            {
                *pOnce = being_initialized;
                _Init_thread_unlock();
                return;
            }
        }
        _Init_thread_epoch = _Init_global_epoch; // _Init_global_epoch = INT_MIN
    }
 
    _Init_thread_unlock();              // 离开临界区
}
// 代码所在的文件为thread_safe_statics.cpp
extern "C" void __cdecl _Init_thread_header(int* const pOnce) noexcept
{
    _Init_thread_lock();                // 进入临界区
 
    if (*pOnce == uninitialized)        // uninitialized = 0
    {
        *pOnce = being_initialized;     // being_initialized = -1
    }
    else
    {
        while (*pOnce == being_initialized)
        {
            // Timeout can be replaced with an infinite wait when XP support is
            // removed or the XP-based condition variable is sophisticated enough
            // to guarantee all waiting threads will be woken when the variable is
            // signalled.
            _Init_thread_wait(xp_timeout);
 
            if (*pOnce == uninitialized)
            {
                *pOnce = being_initialized;
                _Init_thread_unlock();
                return;
            }
        }
        _Init_thread_epoch = _Init_global_epoch; // _Init_global_epoch = INT_MIN
    }
 
    _Init_thread_unlock();              // 离开临界区
}
// 代码所在的文件为thread_safe_statics.cpp
extern "C" void __cdecl _Init_thread_footer(int* const pOnce) noexcept
{
    _Init_thread_lock();
    ++_Init_global_epoch;
    *pOnce = _Init_global_epoch;
    _Init_thread_epoch = _Init_global_epoch;
    _Init_thread_unlock();
    _Init_thread_notify();
}
// 代码所在的文件为thread_safe_statics.cpp
extern "C" void __cdecl _Init_thread_footer(int* const pOnce) noexcept
{
    _Init_thread_lock();
    ++_Init_global_epoch;
    *pOnce = _Init_global_epoch;
    _Init_thread_epoch = _Init_global_epoch;
    _Init_thread_unlock();

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2023-12-9 22:04 被baolongshou编辑 ,原因:
上传的附件:
收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 4975
活跃值: (3878)
能力值: ( LV13,RANK:270 )
在线值:
发帖
回帖
粉丝
2
mac os 平台留给观众自己分析一下了
2023-12-9 21:32
0
雪    币: 3535
活跃值: (31016)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2023-12-9 23:33
1
游客
登录 | 注册 方可回帖
返回
//