Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

group_vector_elements panics during account code compilation #277

Closed
JohnDonavon opened this issue May 4, 2024 · 2 comments
Closed

group_vector_elements panics during account code compilation #277

JohnDonavon opened this issue May 4, 2024 · 2 comments

Comments

@JohnDonavon
Copy link

JohnDonavon commented May 4, 2024

group_vector_elements
panics during account compilation for wasm built with rust nightly compiler or rust stable version 1.78.0

A simple example can be seen here: https://github.com/JohnDonavon/AssemblyWasm/blob/john-test/rust_lib/src/lib.rs

If you set the rust compiler to version 1.77.x, build the wasm (via wasm-pack or however you wish), and run the complile function from the browser it works. However, if you build this wasm with version 1.78.0 or nightly, the TransactionKernel assembler fails to compile the module and panics at the above mentioned function.

I've rewritten the function locally and the account code compiles successfully after. Here is the rewrite if it ends up being helpful:

pub fn group_vector_elements_2<T, const N: usize>(source: Vec<T>) -> Vec<[T; N]> {
    assert_eq!(
        source.len() % N,
        0,
        "source length must be divisible by {}, but was {}",
        N,
        source.len()
    );

    // Capacity of the new vector
    let capacity = source.len() / N;
    let mut result = Vec::with_capacity(capacity);

    // SAFETY: We ensure the source length is exactly divisible by N
    // Convert Vec<T> into Vec<[T; N]>
    unsafe {
        // Convert source into a raw pointer for further manipulation
        let mut source_ptr = source.as_ptr();
        std::mem::forget(source); // Avoid destructor being called

        for _ in 0..capacity {
            // Point to an array of N elements. We advance by N each iteration.
            let array_ptr = source_ptr as *const [T; N];
            // Copy the array. This avoids aliasing issues by not modifying source_ptr directly.
            let array = std::ptr::read(array_ptr);
            result.push(array);
            source_ptr = source_ptr.add(N); // Move the pointer by N elements
        }
    }

    result
}
@irakliyk
Copy link
Collaborator

irakliyk commented May 8, 2024

Very interesting! Thank you for reporting this! I'm curious if the following modification would also fix the issue:

pub fn group_vector_elements<T, const N: usize>(mut source: Vec<T>) -> Vec<[T; N]> {
    assert_eq!(
        source.len() % N,
        0,
        "source length must be divisible by {}, but was {}",
        N,
        source.len()
    );

    let len = source.len() / N;
    let cap = source.capacity() / N;

    // reduce the capacity of the vector to make sure it is a multiple of N
    source.shrink_to(cap * N);

    // convert the vector to a pointer but make sure we don't deallocate the underlying memory
    let mut v = mem::ManuallyDrop::new(source);
    let p = v.as_mut_ptr();

    // build a new vector from the same memory with new length and capacity
    unsafe { Vec::from_raw_parts(p as *mut [T; N], len, cap) }
}

@irakliyk
Copy link
Collaborator

irakliyk commented May 9, 2024

Closed by #282 where we decided to remove this function as there are equivalent standard alternatives available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants