V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
bli22ard
V2EX  ›  程序员

rust 中看似非常简单操作,竟然导致段错误

  •  
  •   bli22ard · 6 天前 · 2241 次点击

    环境

    windows wsl
    DISTRIB_ID=Ubuntu
    DISTRIB_RELEASE=20.04
    DISTRIB_CODENAME=focal
    DISTRIB_DESCRIPTION="Ubuntu 20.04.6 LTS
    arch x86_64
    
    rust version
    stable-x86_64-unknown-linux-gnu (default)
    rustc 1.83.0 (90b35a623 2024-11-26)
    

    Cargo.toml

    [package]
    name = "demo"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    reqwest = {version = "0.11",default-features = false,features = ["rustls-tls"]}
    tokio = {version = "1.42",features = ["full"]}
    
    

    复现方法

    main.rs

    
    #[tokio::main]
    async fn main() {
        let mut tasks=vec![];
        for _i in 0..2{
            let t=tokio::spawn(async move {
                let result=reqwest::get("https://github.com").await;
                if let Ok(result) = result {
                    println!("{:?}",result.status());
                }
            });
            tasks.push(t);
        }
        for t in tasks {
            t.await.expect("Something went wrong");
        }
    }
    
    
    ```bash
    
    root@computer1:/demo/# RUSTFLAGS="-Ctarget-feature=+crt-static" cargo run --target x86_64-unknown-linux-gnu
    
    root@computer1:/demo/# Segmentation fault
    

    原因

    在开启静态链接情况下,该代码会导致段错误。具体导致的原因 hyper#2537
    主要是因为"github.com:443".to_socket_addrs(); 并发会导致段错误。
    main.rs 这个代码也可以出发这个段错误

    use std::net::ToSocketAddrs;
    
    #[tokio::main]
    async fn main() {
        let mut tasks=vec![];
        for _i in 0..2{
            let t=tokio::spawn(async move {
                // let result=reqwest::get("https://github.com").await;
                // if let Ok(result) = result {
                //     println!("{:?}",result.status());
                // }
                "github.com:443".to_socket_addrs();
            });
            tasks.push(t);
        }
        for t in tasks {
            t.await.expect("Something went wrong");
        }
    }
    

    更底层的原因是,这位老哥的说的getaddrinfo

    个人看法

    这意味着你要静态链接,http 或者其他什么涉及到主机名转换并发调用了 getaddrinfo 就会大概率会出现段错误,进程就会直接没了。rust 的静态链接和交叉编译,太菜鸡了😂。 如果你不使用静态链接,而使用动态链接,那么你最好保证你的开发机器软件包版本和你生产环境的软件版本保持一致,不然动态链接 openssl ,在生成看起来已经安装了 openssl ,但是提示找不到😮‍💨。静态链接这一点,golang👍️践踏 rust👎️

    18 条回复    2024-12-17 09:34:25 +08:00
    aloxaf
        1
    aloxaf  
       6 天前
    issue 里和 stackoverflow 里不都说了么,glibc 压根不支持静态链接,尤其是 gethostbyname 。

    想静态链接就用 musl ,ssl 切换到 rustls 。
    dilfish
        2
    dilfish  
       6 天前 via Android
    这个问题我遇到过,你想静态编译 redis 也会警告。

    go 是自己写了一套,rust 也有对应的库,
    wolfsun
        3
    wolfsun  
       6 天前   ❤️ 9
    同意楼上,楼主非要踩一捧一,在智商这一点,狗👍️践踏楼主👎️
    virusdefender
        4
    virusdefender  
       6 天前
    glibc 根本不能静态链接,有些里面的函数你用到的时候还会动态寻找其他的 so ,比如一些密码类的
    hingle
        5
    hingle  
       6 天前
    OP 就是专门踩 rust 捧 go 的。https://v2ex.com/t/1090526
    bli22ard
        6
    bli22ard  
    OP
       6 天前
    @aloxaf
    我测试了一下,musl 静态链接这个代码确实没有问题。linux 静态链接还是得 musl 。
    @dilfish 下次可以试试 musl 静态链接


    @virusdefender 看来 glibc 确实是不能静态链接。即使静态链接编译成功也是假象,段错误在运行时等着。
    bli22ard
        7
    bli22ard  
    OP
       6 天前
    @wolfsun 上来就开喷,不进行一下准备工作吗?比如列一丁点事实?
    bli22ard
        8
    bli22ard  
    OP
       6 天前
    @hingle 列的都是客观事实
    adoal
        9
    adoal  
       6 天前   ❤️ 1
    glibc 大毒瘤
    dogfeet
        10
    dogfeet  
       6 天前
    我都是:

    不使用 native-tls ,专用 rustls
    使用 cargo zigbuild ,还可以指定 glibc 版本,挺无脑的,没你说的那么费劲。
    dogfeet
        11
    dogfeet  
       6 天前
    对了,刚忘说了,我是直接在 windows 上交叉编译 linux 的。安装下 ziglang 和 zigbuild 就行了。
    没觉得比 Golang 麻烦在哪里。
    kagenomirai
        12
    kagenomirai  
       6 天前
    OP 说的也不算事实。链接不是 rust 的责任。你换了 C C++ 或者 D 你都得链接一个 libc ,除非你不调系统的 api 或者有一层 vm 的包装。而 glibc 众所周知是不可以静态链接的。rust 这类系统级编程语言是不可能脱离 c 的 api ,顶多帮你做一些 dirty work ,到头来免不了做系统层面上的兼容。所有 OP 拿 go 和 rust 比就好像拿 lua 和 c 比一样,都不是同一个类语言,在设计上解决的问题也不同。
    归根结底,比较两个(针对某一问题设计的)语言根本没有意义。比较锤子和螺丝刀有意义吗?
    bli22ard
        13
    bli22ard  
    OP
       6 天前
    @adoal 感觉有点道理


    @dogfeet cargo zigbuild 没试过,我是用 https://github.com/cross-rs/cross 交叉编译。zigbuild 不静态链接,到运行的机器容易提示找不到对应 so 吧?静态链接,最佳实战应该就是 musl 了。



    @kagenomirai
    glibc 众所周知是不可以静态链接的,这个我见识短,之前不知道。
    和 lua 比不合适,lua 需要依赖解释器。rust 和 golang 编译输出都是可执行程序,所以它们比较有可比性。编译和链接这块 golang 难道不比 rust 方便? go buid 指定 os 和 arch ,就可以了。
    dogfeet
        14
    dogfeet  
       5 天前
    @bli22ard 是的,想要不依赖 glibc 就用 musl ,想要不依赖 openssl ,就是用 rustls 。
    至于要方便的交叉编译,直接使用 cargo zigbuild 就行。

    大致就是这么简单。
    dogfeet
        15
    dogfeet  
       5 天前
    @dogfeet 我一般还是用 glibc ,但是不用 native-tls(openssl)。虽然很多人说 musl 性能较 musl 差,但其实我并不在乎这个,只是没觉得 glibc 问题有那么严重。毕竟这玩意和内核关系紧密,不像 openssl 。
    在加上 zigbuild 能很方便的指定 glibc 的版本,没觉得这个有啥麻烦的地方。所以继续 glibc
    bli22ard
        16
    bli22ard  
    OP
       5 天前
    @dogfeet zigbuild 我试了下,使用 rustls , 指定低版本的 glibc ,比如 2.22 ,那大多数服务器都可以兼容,不知道这样做有没有什么坏处
    capric
        17
    capric  
       5 天前
    建议用 https://github.com/rust-cross/cargo-zigbuild 或者 https://github.com/cross-rs/cross 静态链接 musl ,不要静态链接 glibc ,可以动态链接 2012 年的 glibc2.17 ,就可以在主流相同指令集的 linux 上跑起来,比如 cargo zigbuild --target aarch64-unknown-linux-gnu.2.17
    bli22ard
        18
    bli22ard  
    OP
       6 小时 8 分钟前
    > 建议用 https://github.com/rust-cross/cargo-zigbuild 或者 https://github.com/cross-rs/cross 静态链接 musl ,不要静> 态链接 glibc ,可以动态链接 2012 年的 glibc2.17 ,就可以在主流相同指令集的 linux 上跑起来,比如 cargo zigbuild > --target aarch64-unknown-linux-gnu.2.17


    @capric rust 编译最佳实战 👍️
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5467 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 07:42 · PVG 15:42 · LAX 23:42 · JFK 02:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.