elrnv / dync Goto Github PK
View Code? Open in Web Editor NEWAn efficient alternative to `dyn Trait` for containerized types
License: Apache License 2.0
An efficient alternative to `dyn Trait` for containerized types
License: Apache License 2.0
Hey there, I noticed that in VecCopy
the backing storage for the Vec is a u8
.
Lines 64 to 65 in c133056
I believe this let's you trigger undefined behavior in the form of misaligned memory access through safe rust code by instantiating a VecCopy
with a type that has different alignment requirements from u8
. Running the following program under miri:
#![forbid(unsafe_code)]
use dync::{VecCopy, VTable};
#[repr(align(256))]
#[derive(Copy, Clone)]
struct LargeAlign(u8);
impl VTable<LargeAlign> for LargeAlign {
fn build_vtable() -> Self {
LargeAlign(0)
}
}
fn main() {
// The backing storage for a VecCopy is a u8, meaning that casting to a type
// with different alginment requires triggers undefined behavior.
// https://github.com/elrnv/dync/blob/c133056676582dd0e28c14526175d0c9ae01a905/src/vec_copy.rs#L64-L65
let mut x = VecCopy::<LargeAlign>::with_type();
x.push_as::<LargeAlign>(LargeAlign(0));
let _ref_to_element = x.get_ref_as::<LargeAlign>(0).unwrap();
}
results in:
❯ cargo miri run
error: Undefined Behavior: accessing memory with alignment 8, but alignment 256 is required
--> /home/ammar/.cargo/registry/src/github.com-1ecc6299db9ec823/dync-0.4.0/src/vec_copy.rs:523:23
|
523 | Some(unsafe { &*ptr.add(i) })
| ^^^^^^^^^^^^ accessing memory with alignment 8, but alignment 256 is required
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
= note: inside `dync::VecCopy::<LargeAlign>::get_ref_as::<LargeAlign>` at /home/ammar/.cargo/registry/src/github.com-1ecc6299db9ec823/dync-0.4.0/src/vec_copy.rs:523:23
note: inside `main` at src/main.rs:41:27
--> src/main.rs:41:27
|
41 | let _ref_to_element = x.get_ref_as::<LargeAlign>(0).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: inside `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
= note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/sys_common/backtrace.rs:137:18
= note: inside closure at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:66:18
= note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:259:13
= note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:381:40
= note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:345:19
= note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panic.rs:382:14
= note: inside `std::rt::lang_start_internal` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:51:25
= note: inside `std::rt::lang_start::<()>` at /home/ammar/.rustup/toolchains/nightly-2020-09-24-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/rt.rs:65:5
error: aborting due to previous error
The #[dync_trait]
and #[dync_mod]
macros should produce vtable functions for user provided trait methods.
Currently only a small handful of traits are supported. This is not too useful in general.
A number of traits would be necessary to enable the use of Values in other std containers like BTreeSet/BTreeMap and other custom containers.
This will probably require a bit of refactoring to write code generators and the like since a number of types need implementations (Value, ValueRef, VecCopy, VecDrop, etc.) for each new trait.
The issue is that currently too many variations of types need to be maintained. More precisely there are Copy vs Drop variants, Owned vs Refereced (Vec vs Slice), Immutable vs Mutable types (ValueRef vs ValueMut). It is a maintenance burden on the implementation as well as API to have these around. I think this is fixable, especially because these types share a lot of functionality.
Notes:
Drop variants of all the types can also contain copy types, whereas the copy variants are more restricted. It doesn't seem like there is any performance penalty for using the Drop value/container types for Copy types so it's reasonable to simply deprecate the Copy variants from the public API or simply document the restricted use cases for the Copy variants.
It seems like there is no way around Ref and Mut variants though it is still possible to unify their implementations using macros.
Following the pattern of the standard library it would be preferable to have the Owned variants to deref to borrowed variants in some way, which will allow us avoid replicating the API for both owned and referenced variants of types. It is unclear how to do this reliably yet since the Deref
and DerefMut
traits expect &
type references instead of custom ones. The example of how this works currently in the standard library is the RefCell
and Ref
types which have an awkward but possibly necessary API.
Further it is worth noting that trying to implement this functionality using DST is not possible without copying data because the TypeId and vtable would need to be stored alongside the data itself, which is not how its stored in the Vec
or Slice
types.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.