Skip to content

Commit

Permalink
Mark push_next() as unsafe and add push_next_one() alternative
Browse files Browse the repository at this point in the history
`push_next()` is totally `unsafe` because of dereferencing a chain of
`p_next` pointers to find the end of the chain to insert, which was
obfuscated by a large `unsafe` block for the `BaseOutStructure` pointer
cast in commit c8c8f69 ("`next` can contain a pointer chain and we need
to correct insert it.").

While this function should definitely be marked unsafe, wrapping
builders in `unsafe {}` en masse in user code isn't all too desirable,
especially when this soundness issue only exists to optionally
walk a `p_next` chain while most users are likely inserting bare
structs without pointer chains most of the time.  `push_next_one()`
is introduced for this reason, remaining safe to call without any
unintended raw pointer dereferences.
  • Loading branch information
MarijnS95 committed Apr 14, 2024
1 parent 660553c commit 0ddf2d2
Show file tree
Hide file tree
Showing 4 changed files with 3,230 additions and 779 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,19 +91,20 @@ let device: Device = instance

### Pointer chains

Use `base.push_next(ext)` to insert `ext` at the front of the pointer chain attached to `base`.
Use `base.push_next_one(ext)` to insert `ext` at the front of the pointer chain attached to `base`. If `ext` already contains a pointer chain of its own,
call `unsafe` `push_next()` instead.

```rust
let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::default();
let mut corner = vk::PhysicalDeviceCornerSampledImageFeaturesNV::default();

let mut device_create_info = vk::DeviceCreateInfo::default()
.push_next(&mut corner)
.push_next(&mut variable_pointers);
.push_next_one(&mut corner)
.push_next_one(&mut variable_pointers);
```

The generic argument of `.push_next()` only allows valid structs to extend a given struct (known as [`structextends` in the Vulkan registry](https://registry.khronos.org/vulkan/specs/1.3/styleguide.html#extensions-interactions), mapped to `Extends*` traits).
Only structs that are listed one or more times in any `structextends` will implement a `.push_next()`.
The generic argument of `.push_next_one()` only allows valid structs to extend a given struct (known as [`structextends` in the Vulkan registry](https://registry.khronos.org/vulkan/specs/1.3/styleguide.html#extensions-interactions), mapped to `Extends*` traits).
Only structs that are listed one or more times in any `structextends` will implement a `.push_next_one()`.

### Flags and constants as associated constants

Expand Down
4 changes: 2 additions & 2 deletions ash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,8 @@ mod tests {
<*mut _>::cast(&mut corner),
];
let mut device_create_info = vk::DeviceCreateInfo::default()
.push_next(&mut corner)
.push_next(&mut variable_pointers);
.push_next_one(&mut corner)
.push_next_one(&mut variable_pointers);
let chain2: Vec<*mut vk::BaseOutStructure<'_>> = unsafe {
vk::ptr_chain_iter(&mut device_create_info)
.skip(1)
Expand Down
Loading

0 comments on commit 0ddf2d2

Please sign in to comment.