C++ 中文周刊 2024-07-06 第163期

周刊项目地址

公众号

点击「查看原文」跳转到 GitHub 上对应文件,链接就可以点击了

qq群 点击进入

RSS

欢迎投稿,推荐或自荐文章/软件/资源等,评论区留言

本期文章由 HMY lhmouse赞助


资讯

标准委员会动态/ide/编译器信息放在这里

最近陆陆续续又有很多c++26 St Louis参会报告出来,这里列一下

Mateusz Pusz

Arthur O’Dwyer

草药老师

reddit网友

另外上周也介绍了mick的报告

另外Ykiko也写了一个 St. Louis WG21 会议回顾

另外安全方面,openssh重大漏洞

OpenSSH 鉴权超时终止会话时信号竞态条件漏洞,可远程攻击,可拿root shell

2020年10月到24年5月之间的版本全部中招,请及时打补丁

本台记者lhmouse报道

openssh cve问题回溯

我们在 OpenSSH 的服务器(sshd)中发现了一个漏洞(信号处理器竞赛条件):如果客户端没有在 LoginGraceTime 秒(默认为 120 秒,旧版本为 600 秒)内进行身份验证,那么 sshd 的 SIGALRM 处理器就会被异步调用,但这个信号处理器会调用各种非异步信号安全的函数(例如 syslog())。这种竞赛条件会影响默认配置下的 sshd。

经调查,我们发现该漏洞实际上是 CVE-2006-5051 的回归(”4.4 之前 OpenSSH 中的信号处理器竞赛条件允许远程攻击者导致拒绝服务(崩溃),并可能执行任意代码”),该漏洞由 Mark Dowd 于 2006 年报告。

这一回归是在 2020 年 10 月(OpenSSH 8.5p1)的 752250c 号提交(”修订 OpenSSH 的日志基础架构”)中引入的,该提交意外删除了 sigdie() 中的 “#ifdef DO_LOG_SAFE_IN_SIGHAND”,而 sigdie() 是 sshd 的 SIGALRM 处理程序直接调用的函数。换句话说

如果未针对 CVE-2006-5051 进行回传修补,或未针对 CVE-2008-4109 进行修补(CVE-2008-4109 是针对 CVE-2006-5051 的不正确修补),OpenSSH < 4.4p1 就容易受到此信号处理器竞赛条件的影响; 4.4p1 <= OpenSSH < 8.5p1 不会受到此信号处理器竞赛条件的影响(因为 CVE-2006-5051 补丁在 sigdie() 中添加的 “#ifdef DO_LOG_SAFE_IN_SIGHAND “将此不安全函数转换为安全的 _exit(1) 调用); 8.5p1 <= OpenSSH < 9.8p1 会再次出现这种信号处理竞赛条件(因为 “#ifdef DO_LOG_SAFE_IN_SIGHAND” 被意外地从 sigdie() 中删除了)。

鉴定为和之前xz 被植入木马一样的问题

开源社区并不是免费的,得盯着相关更新了

(安全的同事应该是在关注的。不过这些年降本增效第一个裁的就是安全吧)

文章

Can you change state in a const function in C++? Why? How?

const_cast

Cooperative Interruption of a Thread in C++20

介绍stop_token,其实就是塞了个状态回调,规范化了一下 直接看代码

#include <chrono>
#include <iostream>
#include <thread>
#include <vector>

using namespace::std::literals;

auto func = [](std::stop_token stoken) {                             // (1)
        int counter{0};
        auto thread_id = std::this_thread::get_id();
        std::stop_callback callBack(stoken, [&counter, thread_id] {  // (2)
            std::cout << "Thread id: " << thread_id 
                      << "; counter: " << counter << '\n';
        });
        while (counter < 10) {
            std::this_thread::sleep_for(0.2s);
            ++counter;
        }
    };

int main() {
    std::vector<std::jthread> vecThreads(10);
    for(auto& thr: vecThreads) thr = std::jthread(func);
  
    std::this_thread::sleep_for(1s);                              // (3)    
    for(auto& thr: vecThreads) thr.request_stop();                // (4)
}

A 16-byte std::function implementation.

直接贴代码吧

template<typename T>
struct sfunc;

template<typename R, typename ...Args>
struct sfunc<R(Args...)> {
    struct lambda_handler_result {
        void* funcs[3];
    };

    enum class tag {
        free,
        copy,
        call 
    };

    lambda_handler_result (*lambda_handler)(void*, void**) {nullptr};
    void* lambda {nullptr};

    template<typename F>
    sfunc(F f) { *this = f;}
    sfunc() {}
    sfunc(const sfunc& f) { *this = f; }
    sfunc(sfunc&& f) { *this = f; }

    sfunc& operator = (sfunc&& f) {
        if(&f == this){
            return *this;
        }
        lambda_handler = f.lambda_handler;
        lambda = f.lambda;
        f.lambda_handler = nullptr;
        f.lambda = nullptr;
        return *this;
    }

    void free_lambda() {
        if(lambda_handler) {
            auto ff {lambda_handler(lambda, nullptr).funcs[(int)tag::free]};
            if(ff){
                ((void(*)(void*))ff)(lambda); 
            }
        }
        lambda = nullptr;
    }

    sfunc& operator = (const sfunc& f) {
        if(&f == this) {
            return *this;
        }
        free_lambda();
        lambda_handler = f.lambda_handler;
        if(f.lambda) {
            auto ff {lambda_handler(lambda, nullptr).funcs[(int)tag::copy]};
            if(ff) {
                ((void(*)(void*, void**))ff)(f.lambda, &lambda); 
            } else { 
                lambda = f.lambda;
            }
        }
        return *this;
    }

    template<typename ...>
    struct is_function_pointer;

    template<typename T>
    struct is_function_pointer<T> {
        static constexpr bool value {false};
    };

    template<typename T, typename ...Ts>
    struct is_function_pointer<T(*)(Ts...)> {
        static constexpr bool value {true};
    };

    template<typename F>
    auto operator = (F f) {
        if constexpr(is_function_pointer<F>::value == true) {
            free_lambda();
            lambda = (void*)f;
            lambda_handler = [](void* l, void**) {
                return lambda_handler_result{/* 两个括号jekyll报错*/{nullptr, nullptr, (void*)+[](void* l, Args... args) {
                    auto& f {*(F)l};
                    return f(forward<Args>(args)...);
                }}};
            };
        } else {
            free_lambda();
            lambda = {new F{f}};
            lambda_handler = [](void* d, void** v) {
                return lambda_handler_result{/* 两个括号jekyll报错*/{(void*)[](void*d){ delete (F*)d;},
                                          (void*)[](void*d, void** v){ *v = new F{*((F*)d)};},
                                          (void*)[](void* l, Args... args)
                                          {
                                              auto& f {*(F*)l};
                                              return f(forward<Args>(args)...);
                                          }}};
            };
        }
    }

    inline R operator()(Args... args) {
        return ((R(*)(void*, Args...))lambda_handler(nullptr, nullptr).funcs[(int)tag::call])(lambda, forward<Args>(args)...);
    }

    ~sfunc() { free_lambda(); }
};

没SSO

A Type for Overload Set

函数没有类型,直接赋值是不可以的

void f(int);
void f(int, int);
// `f` is an overload set with 2 members

auto g = f;  // error! cannot deduce the type of `g`

// This is because:
using FF = decltype(f);  // error! overload set has not type
std::invocable<int> auto g = f;  // error! cannot deduce the type of `g`

// bind invoke也不行,他们要接受对象

而lambda有类型,即使这个类型看不到,那么就可以封装一层

#include <cassert>
#include <utility>

int g(int x) { return x + 1; }
int g(int x, int y) { assert(false); }

class MyClass {
public:
    int f(int x) { return x + 1; }
    int f(int x, int y) { assert(false); }
};

#define OVERLOAD(...) [&](auto &&... args) -> decltype(auto) { \
    return __VA_ARGS__(std::forward<decltype(args)>(args)...); \
}

int main(int argc, char *argv[]) {
    assert(OVERLOAD(g)(5) == 6);
    MyClass obj;
    assert(OVERLOAD(obj.f)(5) == 6);
	return 0;
}

godbolt

P3312就是这盘饺子

Compile-time JSON deserialization in C++

没看懂

Beating NumPy’s matrix multiplication in 150 lines of C code

代码在这 https://github.com/salykova/matmul.c

感觉不是很靠谱,影响因素太多了

视频

C++ Weekly - Ep 435 - Easy GPU Programming With AdaptiveCpp (68x Faster!)

介绍opensycl的

自己看吧,我不是业内,不了解

Björn Fahller: Cache friendly data + functional + ranges = ❤️ https://www.youtube.com/watch?v=3Rk-zSzloL4&ab_channel=SwedenCpp

他这个SOA库还挺有意思的

开源项目介绍

互动环节

团建了一波,定的酒店露天自助,人均四百,吃出了80的感觉,亏麻

酒店内的餐饮服务还是太坑


上一期

看到这里或许你有建议或者疑问或者指出错误,请留言评论! 多谢! 你的评论非常重要!也可以帮忙点赞收藏转发!多谢支持! 觉得写的不错那就给点吧, 在线乞讨 微信转账