RuntimeError: доступ к памяти вне пределов при попытке сохранить строку в куче Wasm с последующим сохранением указателя на строку в структуре

Я пытаюсь сохранить строку в куче Wasm как Uint8Array после кодирования и сохранения указателя на строку и длины в Struct, чтобы я мог получить доступ к строке позже. Ниже мой код в rust

#[wasm_bindgen]
pub struct CustomString{
    ptr : *const u8,
    len: usize
}

#[wasm_bindgen]
impl CustomString{
    pub fn create(len:usize) -> Self{
        let mut d = Vec::with_capacity(len);
        log!("{}",len);

        CustomString{
            ptr: d.as_ptr(),
            len
        }
    }

    pub fn as_ptr(&self) -> *const u8{
        self.ptr
    }

    pub fn print_string(&self){
        let js = unsafe { std::slice::from_raw_parts(self.ptr, self.len) };
        let js = unsafe { std::str::from_utf8_unchecked(js) };
        log!("{}",js) 
    }
}

Мой побочный код JS выглядит следующим образом:

function myTest (){
    debugger;
    const { memory } = wasm;
    let encoder = new TextEncoder();
    let mystring = "Ujjal";
    let encodedString = encoder.encode(mystring);

    let length = encodedString.length;
    console.log(length)

    let cs = CustomString.create(length);

    let ptr = cs.as_ptr();

    const asBytes = new Uint8Array(memory.buffer, ptr, length);

    asBytes.set(encodedString);

    return cs;

}

let cs = myTest();


function decode(cs){

    cs.print_string();
}

decode(cs);

В идеале он должен печатать данную строку, но показывает какое-то несвязанное нежелательное значение. Не мог понять, что случилось, так как я новичок в ржавчине и wasm.

Это консольное сообщение, которое я получаю, когда запускаю эту, а иногда и ошибку памяти. Журнал консоли


person UJJAL DUTTA    schedule 22.02.2020    source источник
comment
Ошибка памяти возникает при попытке с большой строкой.   -  person UJJAL DUTTA    schedule 22.02.2020


Ответы (2)


В create вы создаете vec d и получаете его указатель, но после завершения функции vec d освобождается, и ваш указатель указывает на недопустимую память.

person draganrakita    schedule 22.02.2020
comment
Спасибо, это была грубая ошибка. - person UJJAL DUTTA; 23.02.2020

Итак, наконец, я смог это понять. Ниже мое решение.

Код ржавчины:

pub struct CustomString{
    ptr : *mut u8,
    len: usize
}

#[wasm_bindgen]
impl CustomString{
    pub fn create(len:usize) -> Self{
        let mut d = String::with_capacity(len);
        // log!("{}",len);
        let ptr = d.as_mut_ptr();
        std::mem::forget(d);
        CustomString{
            ptr,
            len
        }

    }

    pub fn as_ptr(&self) -> *mut u8{
        self.ptr
    }

    pub fn as_string(&self)-> String{
        let m = unsafe { String::from_raw_parts(self.ptr, self.len, self.len) };
        m
    }

    pub fn print_string(&self){
        let m = unsafe { String::from_raw_parts(self.ptr, self.len, self.len) };
        log!("{}",m) 
    }
}

Код JS:

function myCS(string){
    const { memory } = wasm;
    let encoder = new TextEncoder();
    let encodedString = encoder.encode(string);

    let length = encodedString.length;

    let cs = CustomString.create(length);

    let ptr = cs.as_ptr();

    const asBytes = new Uint8Array(memory.buffer, ptr, length);

    asBytes.set(encodedString);

    return cs;

}

Одна из проблем этого решения заключается в том, что оно не очень эффективно. Я тестировал это с 500000 random length strings. Это займет около 4000+ ms.

Есть ли лучший способ сделать это с учетом производительности.

person UJJAL DUTTA    schedule 23.02.2020
comment
Проблема в том, что теперь вы забываете каждую строку, поэтому все они остаются в памяти. Чтобы лучше понять ваш вопрос, было бы полезно узнать, почему вы пытаетесь кодировать настраиваемую строку в первую очередь вместо использования встроенной поддержки wasm-bindgen для кодирования строк. - person RReverser; 28.02.2020