Skip to content

Memory safety: double-free in Soa::append() #43

Description

@Shnatsel

The following unit test, when placed in soa-rs-testing/src/lib.rs, causes miri to report a use-after-free:

mod ub_tests {
    use super::*;

    #[test]
    fn append_clears_source_after_raw_move() {
        // `Soa::append` raw-reads every element out of `other` and pushes those
        // values into `self`, but it leaves `other.len` unchanged and then calls
        // `other.clear()`. For owned fields, `clear` drops the stale source slot
        // and frees the allocation that is now owned by `self`; miri reports UB
        // when `self` later reads/drops the dangling owner.
        #[derive(Soars)]
        struct Owned {
            value: Box<u8>,
        }

        let mut dst = Soa::<Owned>::new();
        let mut src = soa![Owned {
            value: Box::new(1),
        }];

        dst.append(&mut src);
    }
}

You can reproduce it with cargo +nightly miri test --release --workspace

As a double free (or a use-after-free free, depending on how you look at it), this is a memory safety bug and may have security implications.

The issue was discovered by GPT-5.5 xhigh and verified manually before reporting.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions