< 返回版块

豆沙饼 is Louys 发表于 2022-09-19 09:31

Tags:signal,long_jmp,set_jmp

Playground 代码已经提供. 本例子在Rust in Action第十二章提出. 是对信号的处理, 并且使用C库的set_jmp和long_jmp使程序跳转. 问题: 程序执行流程:注册信号捕捉

当程序第三次打印, 会收到一个信号SIGUSR1, 我的问题是为什么程序并没有打印

行100 : println!("early return!");

Ext Link: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&code=%23!%5Bfeature(link_llvm_intrinsics)%5D%0D%0A%23!%5Ballow(non_camel_case_types)%5D%0D%0A%23!%5Bcfg(not(windows))%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%3C1%3E%0D%0A%0D%0Ause%20libc%3A%3A%7B%0D%0A%20%20SIGALRM%2C%20SIGHUP%2C%20SIGQUIT%2C%20SIGTERM%2C%20SIGUSR1%2C%0D%0A%7D%3B%0D%0Ause%20std%3A%3Amem%3B%0D%0A%0D%0Aconst%20JMP_BUF_WIDTH%3A%20usize%20%3D%0D%0A%20%20mem%3A%3Asize_of%3A%3A%3Cusize%3E()%20*%208%3B%0D%0Atype%20jmp_buf%20%3D%20%5Bi8%3B%20JMP_BUF_WIDTH%5D%3B%0D%0A%0D%0Astatic%20mut%20SHUT_DOWN%3A%20bool%20%3D%20false%3B%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%3C2%3E%0D%0Astatic%20mut%20RETURN_HERE%3A%20jmp_buf%20%3D%20%5B0%3B%20JMP_BUF_WIDTH%5D%3B%0D%0Aconst%20MOCK_SIGNAL_AT%3A%20usize%20%3D%203%3B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%3C3%3E%0D%0A%0D%0Aextern%20%22C%22%20%7B%0D%0A%20%20%23%5Blink_name%20%3D%20%22llvm.eh.sjlj.setjmp%22%5D%0D%0A%20%20pub%20fn%20setjmp(_%3A%20*mut%20i8)%20-%3E%20i32%3B%0D%0A%0D%0A%20%20%23%5Blink_name%20%3D%20%22llvm.eh.sjlj.longjmp%22%5D%0D%0A%20%20pub%20fn%20longjmp(_%3A%20*mut%20i8)%3B%0D%0A%7D%0D%0A%0D%0A%23%5Binline%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%3C4%3E%0D%0Afn%20ptr_to_jmp_buf()%20-%3E%20*mut%20i8%20%7B%0D%0A%20%20unsafe%20%7B%20%26RETURN_HERE%20as%20*const%20i8%20as%20*mut%20i8%20%7D%0D%0A%7D%0D%0A%0D%0A%23%5Binline%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%3C4%3E%0D%0Afn%20return_early()%20%7B%0D%0A%20%20let%20franken_pointer%20%3D%20ptr_to_jmp_buf()%3B%0D%0A%20%20unsafe%20%7B%20longjmp(franken_pointer)%20%7D%3B%20%20%20%20%20%20%20%20%20%2F%2F%20%3C5%3E%0D%0A%7D%0D%0A%0D%0Afn%20register_signal_handler()%20%7B%0D%0A%20%20unsafe%20%7B%0D%0A%20%20%20%20libc%3A%3Asignal(SIGUSR1%2C%20handle_signals%20as%20usize)%3B%20%2F%2F%20%3C6%3E%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0A%23%5Ballow(dead_code)%5D%0D%0Afn%20handle_signals(sig%3A%20i32)%20%7B%0D%0A%20%20register_signal_handler()%3B%0D%0A%0D%0A%20%20let%20should_shut_down%20%3D%20match%20sig%20%7B%0D%0A%20%20%20%20SIGHUP%20%3D%3E%20false%2C%0D%0A%20%20%20%20SIGALRM%20%3D%3E%20false%2C%0D%0A%20%20%20%20SIGTERM%20%3D%3E%20true%2C%0D%0A%20%20%20%20SIGQUIT%20%3D%3E%20true%2C%0D%0A%20%20%20%20SIGUSR1%20%3D%3E%20true%2C%0D%0A%20%20%20%20_%20%3D%3E%20false%2C%0D%0A%20%20%7D%3B%0D%0A%0D%0A%20%20unsafe%20%7B%0D%0A%20%20%20%20SHUT_DOWN%20%3D%20should_shut_down%3B%0D%0A%20%20%7D%0D%0A%0D%0A%20%20return_early()%3B%0D%0A%7D%0D%0A%0D%0Afn%20print_depth(depth%3A%20usize)%20%7B%0D%0A%20%20for%20_%20in%200..depth%20%7B%0D%0A%20%20%20%20print!(%22%23%22)%3B%0D%0A%20%20%7D%0D%0A%20%20println!()%3B%0D%0A%7D%0D%0A%0D%0Afn%20dive(depth%3A%20usize%2C%20max_depth%3A%20usize)%20%7B%0D%0A%20%20unsafe%20%7B%0D%0A%20%20%20%20if%20SHUT_DOWN%20%7B%0D%0A%20%20%20%20%20%20println!(%22!%22)%3B%0D%0A%20%20%20%20%20%20return%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%7D%0D%0A%20%20print_depth(depth)%3B%0D%0A%0D%0A%20%20if%20depth%20%3E%3D%20max_depth%20%7B%0D%0A%20%20%20%20return%3B%0D%0A%20%20%7D%20else%20if%20depth%20%3D%3D%20MOCK_SIGNAL_AT%20%7B%0D%0A%20%20%20%20unsafe%20%7B%0D%0A%20%20%20%20%20%20libc%3A%3Araise(SIGUSR1)%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%7D%20else%20%7B%0D%0A%20%20%20%20dive(depth%20%2B%201%2C%20max_depth)%3B%0D%0A%20%20%7D%0D%0A%20%20print_depth(depth)%3B%0D%0A%7D%0D%0A%0D%0Afn%20main()%20%7B%0D%0A%20%20const%20JUMP_SET%3A%20i32%20%3D%200%3B%0D%0A%20%20register_signal_handler()%3B%0D%0A%0D%0A%20%20let%20return_point%20%3D%20ptr_to_jmp_buf()%3B%0D%0A%20%20let%20rc%20%3D%20unsafe%20%7B%20setjmp(return_point)%20%7D%3B%0D%0A%20%20if%20rc%20%3D%3D%20JUMP_SET%20%7B%0D%0A%20%20%20%20dive(0%2C%2010)%3B%0D%0A%20%20%7D%20else%20%7B%0D%0A%20%20%20%20println!(%22early%20return!%22)%3B%0D%0A%20%20%7D%0D%0A%0D%0A%20%20println!(%22finishing!%22)%0D%0A%7D%0D%0A

评论区

写评论
作者 豆沙饼 is Louys 2022-09-25 22:33

大哥牛逼, 学编程时间越长, 越觉得程序bug确实多.程序版本的迭代升级很难保证不会出现新问题.

--
👇
zkx: 我在几个平台都跑过,都遇到了问题:

  • Windows wsl2 输出如下:
#
##
###
[1]    448 segmentation fault  cargo run
  • mac m1 输出如下:
#
##
###
##
#
finishing!

目前只能看出,依赖于编译器的固有功能,无法实现非本地跳转,目测是 llvm 自身的问题。
最后我不再依赖于编译器的固有功能,而是直接调用 C 库就按照预期打印了:

extern "C" {
    pub fn setjmp(_: *mut i8) -> i32;

    pub fn longjmp(_: *mut i8, _: c_int);
}

// 输出如下:
#
##
###
early return!
finishing!

不过这段代码只能在 Unix 下执行,失去了跨平台性。

zkx 2022-09-24 20:51

我在几个平台都跑过,都遇到了问题:

  • Windows wsl2 输出如下:
#
##
###
[1]    448 segmentation fault  cargo run
  • mac m1 输出如下:
#
##
###
##
#
finishing!

目前只能看出,依赖于编译器的固有功能,无法实现非本地跳转,目测是 llvm 自身的问题。
最后我不再依赖于编译器的固有功能,而是直接调用 C 库就按照预期打印了:

extern "C" {
    pub fn setjmp(_: *mut i8) -> i32;

    pub fn longjmp(_: *mut i8, _: c_int);
}

// 输出如下:
#
##
###
early return!
finishing!

不过这段代码只能在 Unix 下执行,失去了跨平台性。

1 共 2 条评论, 1 页