首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么在Rust标准文档中,在ptr::copy_nonoverlapping之后声明“可能触发未定义的行为”

在Rust标准文档中,ptr::copy_nonoverlapping 函数用于从一个内存位置复制一定数量的字节到另一个内存位置,前提是源和目标内存区域不能重叠,并且目标区域必须有足够的空间来容纳要复制的字节。函数原型如下:

代码语言:txt
复制
unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize) -> ()

这个函数被标记为 unsafe,意味着它可能会破坏Rust的安全保证,需要程序员自己保证调用它的安全性。如果在调用 ptr::copy_nonoverlapping 之后声明“可能触发未定义的行为”,这通常是因为以下几个原因:

  1. 源指针和目标指针重叠copy_nonoverlapping 的设计前提是源和目标内存区域不重叠。如果它们重叠了,结果是未定义的。这是因为重叠区域的读写顺序可能会影响最终结果,而编译器可能会进行一些优化,这些优化在重叠的情况下可能会导致错误的结果。
  2. 空指针或无效指针:如果传递给 copy_nonoverlapping 的指针是空指针或者指向无效的内存区域,那么尝试读写这些内存位置将会触发未定义行为。
  3. 目标区域空间不足:如果目标内存区域没有足够的空间来容纳要复制的字节,那么尝试写入超出范围的内存也会触发未定义行为。
  4. 越界访问:如果 count 参数大于源或目标内存区域实际可用的元素数量,那么尝试复制超出范围的数据也会触发未定义行为。

为了避免这些问题,你应该:

  • 确保源和目标指针指向的内存区域不重叠。
  • 确保传递给函数的指针是有效的,不是空指针,并且指向的内存区域是可访问的。
  • 确保目标内存区域有足够的空间来容纳要复制的字节。
  • 确保 count 参数不会导致越界访问。

如果你遵循了上述所有条件,那么使用 ptr::copy_nonoverlapping 应该是安全的。但是,由于这个函数是 unsafe 的,你需要自己承担保证其安全使用的责任。

参考链接:

在实际编程中,如果你发现自己频繁使用 unsafe 代码,可能需要重新考虑你的设计,看看是否有更安全的替代方案。Rust 的安全特性是为了避免许多常见的编程错误,如空指针解引用、数据竞争等,因此在可能的情况下,应该尽量避免使用 unsafe 代码。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

原创:FFI极简应用场景【字符串·传输】浅谈

首先,libc crate是操作系统常用ABI的FFI binding。 一方面,在Cargo.toml中添加libc依赖项·就相当于·在C代码插入一行导入系统头文件的#include语句。...CString::from_raw()导入任意【C字符串】会导致“未定义行为”。 所以,直接由C端程序(或libc::malloc())构造的【字符串·字节序列】还是得由&CStr引用才是最安全的。...std::ptr::null() 构造一个未初始化的只读·空指针 std::ptr::null_mut() 构造一个未初始化的可修改·空指针 std::ptr::copy_nonoverlapping + std::ptr::copy_nonoverlapping() --> CString --> String的组合“暴击”,将C内存上的C字符串逐字节地复制到Rust...即,借助libc::malloc() + std::ptr::copy_nonoverlapping() + std::ptr::write()组合,将Rust内存上的C字符串逐字节地复制到C内存。

94230

【Rust日报】2022-09-27 cargo careful:为你的代码提供更多安全保证

null 字节的情况下调用,copy 或者 copy_nonoverlapping 必须针对内存布局对齐的非 null 指针(非重叠)。...但是,由 rustup 分发的常规标准库是在没有调试断言的情况下编译的,因此用户很难从这些额外检查中受益。...需要注意的是,这自然会比常规调试或发布版本慢,但它比在 Miri 中执行程序要快得多,并且仍然有助于找到一些未定义的行为。...,但是 Axum 中,get 函数却可以接收不同类型的函数指针,这是为什么呢?...典型的思路可能是: 找到可以应用特定优化方法的场景 通过分析,找到这种场景 应用你的优化方法 如果将很多编译优化方法结合起来,编译器的性能就能提升一大截。

27940
  • C语言不是最好的,却是我最爱的~

    在大多数情况下,你都可以预见到编译的结果,即对象在内存中的表示方式,以及如何通过不同的方式理解编译后的结果(新版 C 标准中这一点变得更困难,这都要怪 C++,我稍后再详细介绍)。...例如,无法使用两个不同类型的指针同时操作同一块内存区域。我无法想象为什么这种行为被禁止,其原因只可能是编译器优化。这样就不可能利用联合体将整数转换成浮点数。...但在我看来,这样做的目的或者是更好的编译器优化,或者是出于 C++的要求(由于类型跟踪的要求)。 实现中定义的行为(即超出 C 标准规定的行为)。...我常用的例子就是函数调用:根据调用的习惯约定和编译器的实现,函数的参数的求值顺序可能完全是随机的,因此 foo(*ptr++, *ptr++, *ptr++)的结果是未定义的,因此即使你知道目标体系结构...完全未定义的行为。最常见的例子就是在一条语句中改变变量状态,例如著名的 I++ + i++,或者更甚的 *ptr++ = *ptr++ +*ptr++。

    17510

    为什么我十分喜欢C,却很不喜欢C++?

    在大多数情况下,你都可以预见到编译的结果,即对象在内存中的表示方式,以及如何通过不同的方式理解编译后的结果(新版 C 标准中这一点变得更困难,这都要怪 C++,我稍后再详细介绍)。...例如,无法使用两个不同类型的指针同时操作同一块内存区域。我无法想象为什么这种行为被禁止,其原因只可能是编译器优化。这样就不可能利用联合体将整数转换成浮点数。...但在我看来,这样做的目的或者是更好的编译器优化,或者是出于 C++的要求(由于类型跟踪的要求)。 实现中定义的行为(即超出 C 标准规定的行为)。...我常用的例子就是函数调用:根据调用的习惯约定和编译器的实现,函数的参数的求值顺序可能完全是随机的,因此 foo(*ptr++, *ptr++, *ptr++)的结果是未定义的,因此即使你知道目标体系结构...完全未定义的行为。最常见的例子就是在一条语句中改变变量状态,例如著名的 I++ + i++,或者更甚的 *ptr++ = *ptr++ +*ptr++。

    78610

    从 RUST 库中公开 FFI

    做一些可怕的事情 .. }),但是在这里,整个函数被标记为 unsafe ,因为不正确的使用会导致未定义行为,比如传递 NULL 或 悬空指针。以此告诉调用者应该正确使用它并意识到可能造成的后果。...返回参数 在我的例子中,我想向外部公开一些 Rust 的结构,但是由于实现的原因,它们可能包含一些复杂的结构,而强迫最终用户处理这些东西是一个坏主意。...不过这个函数不需要用unsafe 标记,因为这里不可能创建一些未定义行为。...ptr.is_null()); let battery = &*ptr; battery.energy() } 在引用之后,我只是简单地从 Battery::energy 方法中返回一个...附加说明:我发现这个构建脚本在 docs.rs 中构建文档时出现了一些神秘错误,导致构建失败失败。

    1.9K30

    Unsafe 随堂小测题解(一)

    官方给出的解释为: “健全性是一个类型系统的概念,意味着类型系统是正确的,即,类型良好的程序实际上应该具有该属性。对于 Rust 来说,意味着类型良好的程序不会导致未定义行为。...但是这个承诺只适用于 Safe Rust。对于 Unsafe Rust要有开发者/程序员来维护这个契约。因此,如果Safe 代码的公开 API 不可能导致未定义行为,就可以说这个库是健全的。...反之,如果安全代码导致未定义行为,那么这个库就是不健全的。 也就是说,开发者在编写 Unsafe Rust 代码的时候,有义务来保证提供的安全抽象接口是不会有未定义行为产生的。...因为 在实现 Memory trait 的时候,实现其addr方法存在风险,返回指针可能为空。(标准库中有类似案例:std::str::pattern::Searcher[8])。并且增加文档注释。...需要去看看标准库文档中 set_len的使用安全条件[9]: 传入的参数new_len必须必须小于或等于capacity()。 old_len..new_len 范围内的元素必须被初始化。

    96020

    「转自 InfoQ」Rust:一个不再有 CC++ 的,实现安全实时软件的未来

    在无法保证内存安全的情况下,未定义行为极有可能发生。...Rust 则完全颠覆了这一点,这也是它为什么令人激动的原因。 Rust 的设计目标 无需担心数据的并发运算:只要程序中的不同部分可能在不同的时间或者乱序运行,并发就有可能发生。...不安全的 Rust 如作者之前所说,未定义行为发生的可能性是不能完全被清除的,这是由于底层计算机硬件固有的不安全性导致的。Rust 允许在一个存放不安全代码的模块进行不安全操作。...所以在 std::transform 的第一个循环之后,unique_ptr 很有可能被清空,官方声明是它会处于一种有效但是未知的状态,但是以作者对 Clang 的经验来看它通常会被清空。...后续使用这个空指针时会导致未定义行为,作者运行之后得到了一个空指针错误,在大多数托管系统的空指针解引用都会报这种错误,因为零内存页面通常会被保留。

    1.2K20

    Rust避坑现代C++悬垂指针

    在2023年JetBrains全球开发者生态问卷调查中,C++在受访程序员过去一年中的使用率,占25%,紧跟JavaScript、Python和Java之后。...这种声明后延迟初始化的模式在Rust中是允许的,但要确保在使用变量之前对其进行赋值。编译器此时会进行流程分析,确保变量在被使用前已经被初始化。第6行开始一个新的作用域,用花括号 {} 包围。...代码展示了Rust在安全性和灵活性之间的平衡,以及使用unsafe代码块时可能带来的潜在风险。第4行声明一个裸指针变量,但暂不初始化。第6-14行创建一个新的作用域。...这表明我们正在访问已经被释放的内存,可能是被重新分配给了其他数据。这种行为是未定义的,可能导致程序崩溃或产生不可预测的结果。...这个输出强调了在Rust中正确使用裸指针的重要性,以及为什么Rust通常会阻止这种危险操作。只有在unsafe块中,我们才能执行这种不安全的操作,而且应该非常谨慎地使用。

    58161

    【Rust 基础篇】Rust中的不安全代码:谨慎探索黑盒之门

    在Rust中,不安全代码是指在编写时必须遵循一些特定规则,并且在运行时可能导致不安全行为的代码块。Rust通过unsafe关键字来标识不安全代码块。...实现不安全trait:实现Rust中的不安全trait,需要保证手动处理好相关的安全问题。 值得强调的是,使用不安全代码是有风险的,可能导致未定义行为、空指针、数据竞争等安全问题。...不安全代码的风险和注意事项 使用不安全代码会增加代码的风险,可能导致未定义行为、内存安全问题、数据竞争等。...4.3 尽量使用安全抽象 在大多数情况下,应尽量使用安全的抽象来替代不安全代码。Rust提供了很多安全的高级抽象,如标准库中的数据结构、原子操作、互斥锁等,可以避免使用不安全代码带来的安全风险。...4.4 使用文档和注释 在使用不安全代码时,应该充分注释和文档化代码,说明为什么需要使用不安全代码以及如何确保代码的安全性。这样可以帮助其他开发者理解代码,并避免潜在的错误。

    33820

    Rust 提升安全性的方式

    foo 函数中对 pBar 进行了非空的判断,但 pBar 可能指向了一块已经被释放掉了的内存,也就是所谓的「dangling pointer」错误 2,此时程序的行为是未定义的。...在编译之后的代码中,bar 对象以两个整形变量的形式紧密排布在栈上。...unique_ptr 表达了独占的所有权,如果我们尝试复制指针则会造成编译错误,需要用 std::move 来表达所有权的移动。但是,即便是有了这个移动语义,代码还是可能会出现未定义的行为。...并且,Rust 的编译器在发现一个变量被移动后又被继续使用时,会直接拒绝编译,这个安全保证直接嵌进了语言中,防止出现 C++ 中使用已移动资源的未定义行为。...中也没有违背 Aliasing 和 Mutation 不能同时存在的原则,但它还是造成了一个未定义行为。

    97820

    【Rust 基础篇】Rust中的不安全函数:解锁系统级编程的黑盒之门

    在调用不安全函数的上下文中,必须手动确保调用是安全的,不会导致未定义行为。...不安全函数的风险和注意事项 使用不安全函数会增加代码的风险,可能导致未定义行为、内存安全问题、数据竞争等。...4.3 尽量使用安全抽象 在大多数情况下,应尽量使用安全的抽象来替代不安全函数。Rust提供了很多安全的高级抽象,如标准库中的数据结构、原子操作、互斥锁等,可以避免使用不安全函数带来的安全风险。...4.4 使用文档和注释 在使用不安全函数时,应该充分注释和文档化代码,说明为什么需要使用不安全函数以及如何确保代码的安全性。这样可以帮助其他开发者理解代码,并避免潜在的错误。...尽管不安全函数可能是必要的,但我们应该尽量避免使用不安全函数,使用安全的抽象来代替。同时,我们也要通过文档和注释,让代码的使用和维护变得更加容易。

    23630

    「我读」PL 观点 | 未定义行为有利的一面

    什么是未定义行为 在计算机程序设计中,未定义行为(英语:undefined behavior)是指执行某种计算机代码所产生的结果,这种代码在当前程序状态下的行为在其所使用的语言标准中没有规定。...在这些语言的标准中,规定某些操作的语义是未定义的,典型的例子就是程序错误的情况,比如越界访问数组元素。标准允许语言的具体实现做这样的假设:只要是符合标准的程序代码,就不会出现任何类似的行为。...例如,在CPU的指令集说明中可能将某些形式的指令定为未定义,但如果该CPU支持内存保护,说明中很可能会还会包含一条兜底的规则,要求任何用户态的指令都不会让操作系统的安全性受损;这样一来,在执行未定义行为的指令时...一个符合标准的实现可以在假定未定义行为永远不发生(除了显式使用不严格遵守标准的扩展)的基础上进行优化,可能导致原本存在未定义行为(例如有符号数溢出)的程序经过优化后显示出更加明显的错误(例如死循环)。...Rust 程序员在编写代码过程中要确保不要触发未定义行为。

    1.7K30

    论文导读 | Rudra : 查找 Rust 生态系统中的内存安全 Bug

    Safe Rust 意味着,无论如何都不可能导致未定义行为。换句话说,Safe API 的职责是,确保任何有效的输入不会破坏内部封装的 Unsafe 代码的行为预期。...定义4:如果 在 safe-value(arg(F))集合中存在v (记为:∃ ∈ safe-value(())),使得当调用 F(v)时触发违反内存安全的行为,或者返回一个不属于safe-value(...换句话说,一个安全的函数不应该提供比 Rust 编译器提供的安全不变式更多的东西。所谓 安全不变式就是指 Rust 里的安全函数,在任何有效输入的情况下,都不应该发生任何未定义行为。...例如,Rust 里的 sort 函数,不应该触发任何未定义行为,哪怕用户提供的比较器不遵循全序关系,也不会发生段错误。...由于其普遍性和微妙性,Rust标准库现在明确指出[5],用一个未初始化的缓冲区调用read()本身就是不健全的行为。

    98920

    先别急着“用Rust重写”,可能没有说的那么安全

    然而,C 和 Rust 代码联合体静默调用了未定义的行为,结合具体的架构、Rust 版本和 LLVM 版本,这有可能引发内存安全问题。 在实践当中,这个问题不涉及人为因素,而且很难加以预防。...换言之,我们假定原始代码本身符合内存安全要求,只考虑两段代码间 FFI 层处可能出现的内存不安全和未定义行为。...目前 rusTLS 还无法检测到 double-free:读取“freed”Arc 引用的计数会首先触发未定义行为 [rustls-#32]。...至于显式 bug,请注意图一中的 rustls_client_cert_verifier_new 并不属于异常安全,因为对 RootCertStore 的克隆可能会触发未经处理的内存不足 panic 并跨...打包器会使用与 C 兼容的等效类型(指原始指针及其长度等效)替换缓冲区切片,从而导致类型别名。这可能引发 Rust FFI 中的未定义行为和 LLVM 的不合理优化。

    43430

    【译】为 嵌入式 C 程序员编写的 Rust 指南

    (data race)都是不可能的;这也适用于其他大多数传统上被认为是C语言中未定义行为的东西。︎...由于IRQ控制流的存在,可变全局变量也可能成为其他恶意行为的来源。因此,对可变全局的读写,或者创建对其的引用,都需要使用Unsafe的Rust。 函数 在C和Rust中,函数是最重要的句法结构。...外部符号的名称可以使用extern块进行 "前向声明",这使得Rust可以命名这些符号,并在之后与之链接。...Unsafe 的Rust对未定义行为并不安全,它可以让机器处于正常安全的Rust所允许的行为会触发未定义行为的状态。一般来说,有几条经验法则是有用的。...每当 unsafe 的代码调用到一个unsafe 的函数时,它必须确保在安全的代码中观察不到违反的不变性,这些不变性可能会触发未定义行为。

    5.2K30

    Reddit 观察 | 以排序为案例,对 CCPPRust 安全与性能的相关性研究

    先上简单结论: 在用户定义的比较函数中,复杂的通用实现与追求性能的组合,使得通用高性能排序实现在避免每种使用场景下的未定义行为(UB)方面特别困难。...Rust 实现 Rust标准库的排序接口在许多情况下避免了这个问题,它要求用户定义的比较函数返回 Ordering 类型而不是bool。...位拷贝会导致使用后释放的未定义行为,很可能以双重释放的形式出现。与 C 选项相同,D 选项但还增加了由于将未初始化的内存解释为类型的有效占用而导致的任意 UB。...Panic safety 主要关心的是在面对 panic 时,代码仍然能保持其内存安全的特性,这意味着即使出现了 panic,也不会导致未定义的行为。...我不明白为什么不能直接从 Rust 转换到 C++,同时满足他们的要求。作者Danila Kutenin在他们的博客文章中甚至提到了 Rust 的实现,所以我认为他们是知道的。

    40120

    听GPT 讲Rust源代码--srctools(29)

    该文件的主要目的是通过静态分析检查代码中的指针类型转换,并提供相关的代码建议以确保可变性不被破坏。在Rust中,指针类型转换可能会导致可变性问题,进而引发未定义行为或者安全漏洞。...该lint的主要目的是避免将不同类型的指针通过类型转换强行转换为另一种指针类型,这可能导致类型不匹配的错误或未定义的行为。...这个lint用于检测指针转换操作中的类型对齐问题。 在C和C++中,进行指针转换时,如果将一个指针从一个类型转换为另一个类型,并且这两个类型的对齐要求不同,会导致未定义行为。...在Rust中,指针类型转换可能会导致潜在的未定义行为或内存安全问题。ptr_as_ptr.rs文件的目的是通过静态分析代码,检测代码中的指针类型转换,并给出相应的警告。...函数指针转换为数字类型可能产生一些问题,例如将一个函数指针视为代表地址的数字可能会引起类型不匹配、溢出和未定义行为等问题。

    15410

    Rust 1.51.0 已正式发布,及其新特性详述

    虽然,这可能会导致一些 crate 编译不止一次,但在对 cargo 使用特性时,这将提供更直观的开发体验。如果您想了解更多信息,还可以阅读 Cargo 文档中的“Resolver 特性”部分。...在 macOS 中,以前的调试信息,是使用一个名为 dsymutil 的工具收集到一个单独的 .dSYM 文件夹中,这可能需要一些时间,并占用大量磁盘空间。...但这又是必要的步骤,因为没有收集和编译,Rust 的标准库将不知道如何在 macOS 上加载调试信息。...Cargo 中启用此新行为。...以前这是不可能的,因为 Rust 要求 &/&mut 对齐,并指向已经初始化的数据,而 &addr as *const _ 将导致未定义的行为,因为 &addr 需要对齐。

    1.3K10

    Rust FFI 编程 - 手动绑定 C 库入门 02

    结构体 结构体是由用户定义的一种复合类型,我们知道不同的语言使用不同的机制在计算机内存中布局数据,这样 Rust 编译器可能会执行某些优化而导致类型布局有所不同,无法和其他语言编写的程序正确交互。...使用repr属性,只可以更改其字段之间的填充,但不能更改字段本身的内存布局。repr(packed)可能导致未定义的行为,不要轻易使用。...我们假定要在 Rust 程序中实现格式化日期格式的功能,可以通过调用这个标准库中的 strftime() 函数来完成。...这个函数使用了指向 C 结构体 tm 的指针,该结构体也必须在 Rust 中重新声明,通过类型布局小节,我们知道可以使用repr属性#[repr(C)]来确保在 Rust 中,该结构体的内存布局与在 C...Rust 中,比较推荐的一种做法是,通过使用一个拥有私有字段的结构体来声明这种类型。

    1.2K20
    领券