Skip to content

Commit

Permalink
fix: Fix freeing access violations
Browse files Browse the repository at this point in the history
  • Loading branch information
benaclejames committed Feb 27, 2024
1 parent 2ce276a commit 65e48fb
Showing 1 changed file with 37 additions and 23 deletions.
60 changes: 37 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::ffi::{c_char, c_uchar, CStr, CString};
use std::mem::forget;
use std::ptr::null;
use std::slice;
use std::{slice};
use std::time::{SystemTime, UNIX_EPOCH};

macro_rules! println {
Expand All @@ -26,7 +25,7 @@ impl Default for OscValue {
}
}

#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone, Copy)]
#[repr(C)]
pub enum OscType {
Null,
Expand All @@ -51,8 +50,8 @@ pub struct OscValue {
#[repr(C)]
pub struct OscMessage {
pub address: *const c_char,
pub value_length: usize,
pub value: Box<[OscValue]>
pub value_length: u32,
pub value: *const OscValue
}

fn extract_osc_address(buf: &[u8], ix: &mut usize) -> Result<String, ParserError> {
Expand Down Expand Up @@ -183,11 +182,10 @@ fn parse(buf: &[u8], index: &mut usize) -> Result<OscMessage, ParserError> {

return match (address, value) {
(Ok(address), Ok(value)) => {

Ok(OscMessage {
address: CString::new(address).unwrap().into_raw(),
value_length: value.len(),
value: value.into_boxed_slice(),
value_length: value.len() as u32,
value: value.into_boxed_slice().as_ptr(),
})
}
(Err(e), _) => {
Expand All @@ -207,7 +205,7 @@ pub extern "C" fn parse_osc(buf: *const c_uchar, len: usize, index: &mut usize)
Ok(parsed_msg) => {
let boxed_message = Box::new(parsed_msg);
let raw_ptr: *const OscMessage = Box::into_raw(boxed_message);
forget(raw_ptr);

raw_ptr
}
Err(_) => null(),
Expand All @@ -216,19 +214,13 @@ pub extern "C" fn parse_osc(buf: *const c_uchar, len: usize, index: &mut usize)

#[no_mangle]
pub unsafe extern "C" fn free_osc_message(ptr: *const OscMessage) {
// Here we convert the ptr back to an osc message, therefore informing GC of it's existence once again
if ptr.is_null() {
return;
}

let message = Box::from_raw(ptr as *mut OscMessage);
for value in message.value.iter() {
if value.string != null() {
let value_str = CString::from_raw(value.string as *mut c_char);
drop(value_str);
}
}
let address = CString::from_raw(message.address as *mut c_char);
// Should defo be freeing strings from the values array here too, but oh well. VRChat doesn't send em anyways
drop(address);
drop(message);
}
Expand All @@ -249,13 +241,14 @@ fn write_address(buf: &mut [u8], ix: &mut usize, address: &str) {
pub extern "C" fn create_osc_message(buf: *mut c_uchar, osc_template: &OscMessage) -> usize {
let buf = unsafe { slice::from_raw_parts_mut(buf, 4096) };
let address = unsafe { CStr::from_ptr(osc_template.address) }.to_str().unwrap();
let values = unsafe { slice::from_raw_parts(osc_template.value, osc_template.value_length as usize) };
let mut ix = 0;
write_address(buf, &mut ix, address);
buf[ix] = 44; // ,
ix += 1;

for i in 0..osc_template.value_length {
let value = &osc_template.value[i];
let value = &values[i as usize];

let type_tag = match value.osc_type {
OscType::Int => 'i', // i
Expand All @@ -279,7 +272,7 @@ pub extern "C" fn create_osc_message(buf: *mut c_uchar, osc_template: &OscMessag
}

for i in 0..osc_template.value_length {
let value = &osc_template.value[i];
let value = &values[i as usize];

match value.osc_type {
OscType::Int => {
Expand All @@ -296,16 +289,15 @@ pub extern "C" fn create_osc_message(buf: *mut c_uchar, osc_template: &OscMessag
}
}


ix
}

// Creates a bundle from an array of OscMessages
#[no_mangle]
pub extern "C" fn create_osc_bundle(buf: *mut c_uchar, messages: *const OscMessage, len: usize, messages_index: *mut usize) -> usize {
pub extern "C" fn create_osc_bundle(buf: *mut c_uchar, messages: *const OscMessage, len: u32, messages_index: &mut usize) -> usize {
// OSC bundles start with the 16 byte header consisting of "#bundle" (with null terminator) followed by a 64-bit big-endian timetag
let buf = unsafe { slice::from_raw_parts_mut(buf, 4096) };
let messages = unsafe { slice::from_raw_parts(messages, len) };
let messages = unsafe { slice::from_raw_parts(messages, len as usize) };
let mut ix = 0;

// Write the header
Expand All @@ -325,7 +317,7 @@ pub extern "C" fn create_osc_bundle(buf: *mut c_uchar, messages: *const OscMessa
ix += 8;

// Now we need to write the messages
let mut message_ix = unsafe { *messages_index };
let mut message_ix = *messages_index;
for msg in messages.iter().skip(message_ix) {
// We need to calculate the length of the string and pad it to a multiple of 4 to ensure alignment
// then add another 4 bytes for the length of the message
Expand All @@ -350,7 +342,7 @@ pub extern "C" fn create_osc_bundle(buf: *mut c_uchar, messages: *const OscMessa
}

// Update the messages_index pointer with the new message index
unsafe { *messages_index = message_ix; }
*messages_index = message_ix;

ix
}
Expand Down Expand Up @@ -422,6 +414,28 @@ mod tests {
Err(_) => assert!(false, "Failed to parse message."),
}
}

#[test]
fn serialize_bundle() {
let mut buf: [c_uchar; 4096] = [0; 4096];
let value1 = OscValue { osc_type: OscType::Float, float: 1.0, ..Default::default() };
let value2 = OscValue { osc_type: OscType::Float, float: 0.5, ..Default::default() };
let value3 = OscValue { osc_type: OscType::Float, float: 0.1, ..Default::default() };
let osc_message1 = OscMessage {
address: CString::new("/tracking/eye/CenterPitchYaw").unwrap().into_raw(),
value_length: 2,
value: [value1, value2].into(),
};
let osc_message2 = OscMessage {
address: CString::new("/tracking/eye/EyesClosedAmount").unwrap().into_raw(),
value_length: 1,
value: [value3; 1].into(),
};
let pp = [osc_message1, osc_message2];
let mut index: usize = 0;
let retSize = create_osc_bundle(buf.as_mut_ptr(), pp.as_ptr(), 2, &mut index);
assert!(retSize != 0)
}
}

#[cfg(test)]
Expand Down

0 comments on commit 65e48fb

Please sign in to comment.