Skip to content

Commit

Permalink
filter: fix double free issues via ndb_filter_clone
Browse files Browse the repository at this point in the history
Signed-off-by: William Casarin <[email protected]>
  • Loading branch information
jb55 committed Feb 9, 2024
1 parent 2d957ad commit 1d65de2
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 52 deletions.
137 changes: 92 additions & 45 deletions src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,46 @@ use crate::Note;
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr::null_mut;
use tracing::debug;

#[derive(Debug, Clone)]
#[derive(Debug)]
pub struct FilterBuilder {
pub data: bindings::ndb_filter,
}

#[derive(Debug)]
pub struct Filter {
pub data: bindings::ndb_filter,
}

impl Clone for Filter {
fn clone(&self) -> Self {
let mut new_filter: bindings::ndb_filter = Default::default();
unsafe {
bindings::ndb_filter_clone(
new_filter.as_mut_ptr(),
self.as_ptr() as *mut bindings::ndb_filter,
);
};
Filter { data: new_filter }
}
}

impl bindings::ndb_filter {
fn as_ptr(&self) -> *const bindings::ndb_filter {
self as *const bindings::ndb_filter
}

fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter {
self as *mut bindings::ndb_filter
}
}

impl Filter {
pub fn new() -> Filter {
impl Default for bindings::ndb_filter {
fn default() -> Self {
let null = null_mut();
let mut filter_data = bindings::ndb_filter {
finalized: 0,
elem_buf: bindings::cursor {
start: null,
p: null,
Expand All @@ -30,96 +54,119 @@ impl Filter {
end: null,
},
num_elements: 0,
current: null_mut(),
elements: [
null_mut(),
null_mut(),
null_mut(),
null_mut(),
null_mut(),
null_mut(),
null_mut(),
],
current: -1,
elements: [0, 0, 0, 0, 0, 0, 0],
};

unsafe {
bindings::ndb_filter_init(&mut filter_data as *mut bindings::ndb_filter);
bindings::ndb_filter_init(filter_data.as_mut_ptr());
};

Self { data: filter_data }
filter_data
}
}

impl Filter {
pub fn new() -> FilterBuilder {
FilterBuilder {
data: Default::default(),
}
}

pub fn matches(&self, note: &Note) -> bool {
unsafe {
bindings::ndb_filter_matches(self.as_ptr() as *mut bindings::ndb_filter, note.as_ptr())
!= 0
}
}

pub fn as_ptr(&self) -> *const bindings::ndb_filter {
return self.data.as_ptr();
}

pub fn as_mut_ptr(&self) -> *mut bindings::ndb_filter {
return self.data.as_ptr() as *mut bindings::ndb_filter;
pub fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter {
return self.data.as_mut_ptr() as *mut bindings::ndb_filter;
}
}

fn add_int_element(&self, i: u64) {
impl FilterBuilder {
pub fn new() -> FilterBuilder {
Self {
data: Default::default(),
}
}

pub fn as_ptr(&self) -> *const bindings::ndb_filter {
return self.data.as_ptr();
}

pub fn as_mut_ptr(&mut self) -> *mut bindings::ndb_filter {
return self.data.as_mut_ptr();
}

fn add_int_element(&mut self, i: u64) {
unsafe { bindings::ndb_filter_add_int_element(self.as_mut_ptr(), i) };
}

fn add_str_element(&self, s: &str) {
fn add_str_element(&mut self, s: &str) {
let c_str = CString::new(s).expect("string to cstring conversion failed");
unsafe {
bindings::ndb_filter_add_str_element(self.as_mut_ptr(), c_str.as_ptr());
};
}

fn add_id_element(&self, id: &[u8; 32]) {
fn add_id_element(&mut self, id: &[u8; 32]) {
let ptr: *const ::std::os::raw::c_uchar = id.as_ptr() as *const ::std::os::raw::c_uchar;
unsafe {
bindings::ndb_filter_add_id_element(self.as_mut_ptr(), ptr);
};
}

fn start_field(&self, field: bindings::ndb_filter_fieldtype) {
fn start_field(&mut self, field: bindings::ndb_filter_fieldtype) {
unsafe { bindings::ndb_filter_start_field(self.as_mut_ptr(), field) };
}

fn start_tags_field(&self, tag: char) {
fn start_tags_field(&mut self, tag: char) {
unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as i8) };
}

fn start_kinds_field(&self) {
fn start_kinds_field(&mut self) {
self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_KINDS);
}

fn start_authors_field(&self) {
fn start_authors_field(&mut self) {
self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_AUTHORS);
}

fn start_since_field(&self) {
fn start_since_field(&mut self) {
self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_SINCE);
}

fn start_limit_field(&self) {
fn start_limit_field(&mut self) {
self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_LIMIT);
}

fn start_ids_field(&self) {
fn start_ids_field(&mut self) {
self.start_field(bindings::ndb_filter_fieldtype_NDB_FILTER_IDS);
}

fn start_events_field(&self) {
fn start_events_field(&mut self) {
self.start_tags_field('e');
}

fn start_pubkeys_field(&self) {
fn start_pubkeys_field(&mut self) {
self.start_tags_field('p');
}

fn start_tag_field(&self, tag: char) {
fn start_tag_field(&mut self, tag: char) {
unsafe { bindings::ndb_filter_start_tag_field(self.as_mut_ptr(), tag as u8 as c_char) };
}

fn end_field(&self) {
fn end_field(&mut self) {
unsafe { bindings::ndb_filter_end_field(self.as_mut_ptr()) }
}

pub fn events(&mut self, events: Vec<[u8; 32]>) -> &mut Filter {
pub fn events(&mut self, events: Vec<[u8; 32]>) -> &mut Self {
self.start_tag_field('e');
for ref id in events {
self.add_id_element(id);
Expand All @@ -128,7 +175,7 @@ impl Filter {
self
}

pub fn ids(&mut self, ids: Vec<[u8; 32]>) -> &mut Filter {
pub fn ids(&mut self, ids: Vec<[u8; 32]>) -> &mut Self {
self.start_ids_field();
for ref id in ids {
self.add_id_element(id);
Expand All @@ -137,7 +184,7 @@ impl Filter {
self
}

pub fn pubkeys(&mut self, pubkeys: Vec<[u8; 32]>) -> &mut Filter {
pub fn pubkeys(&mut self, pubkeys: Vec<[u8; 32]>) -> &mut Self {
self.start_tag_field('p');
for ref pk in pubkeys {
self.add_id_element(pk);
Expand All @@ -146,7 +193,7 @@ impl Filter {
self
}

pub fn authors(&mut self, authors: Vec<[u8; 32]>) -> &mut Filter {
pub fn authors(&mut self, authors: Vec<[u8; 32]>) -> &mut Self {
self.start_authors_field();
for author in authors {
self.add_id_element(&author);
Expand All @@ -155,7 +202,7 @@ impl Filter {
self
}

pub fn kinds(&mut self, kinds: Vec<u64>) -> &mut Filter {
pub fn kinds(&mut self, kinds: Vec<u64>) -> &mut Self {
self.start_kinds_field();
for kind in kinds {
self.add_int_element(kind);
Expand All @@ -164,7 +211,7 @@ impl Filter {
self
}

pub fn pubkey(&mut self, pubkeys: Vec<[u8; 32]>) -> &mut Filter {
pub fn pubkey(&mut self, pubkeys: Vec<[u8; 32]>) -> &mut Self {
self.start_pubkeys_field();
for ref pubkey in pubkeys {
self.add_id_element(pubkey);
Expand All @@ -173,7 +220,7 @@ impl Filter {
self
}

pub fn tags(&mut self, tags: Vec<String>, tag: char) -> &mut Filter {
pub fn tags(&mut self, tags: Vec<String>, tag: char) -> &mut Self {
self.start_tag_field(tag);
for tag in tags {
self.add_str_element(&tag);
Expand All @@ -182,31 +229,31 @@ impl Filter {
self
}

pub fn since(&mut self, since: u64) -> &mut Filter {
pub fn since(&mut self, since: u64) -> &mut Self {
self.start_since_field();
self.add_int_element(since);
self.end_field();
self
}

pub fn limit(&mut self, limit: u64) -> &mut Filter {
pub fn limit(&mut self, limit: u64) -> &mut Self {
self.start_since_field();
self.add_int_element(limit);
self.end_field();
self
}

pub fn matches(&self, note: &Note) -> bool {
unsafe { bindings::ndb_filter_matches(self.as_mut_ptr(), note.as_ptr()) != 0 }
pub fn build(&mut self) -> Filter {
unsafe {
bindings::ndb_filter_end(self.as_mut_ptr());
};
Filter { data: self.data }
}
}

/*
// This is unsafe.. but we still need a way to free the memory on these
impl Drop for Filter {
fn drop(&mut self) {
debug!("dropping filter {:?}", self);
unsafe { bindings::ndb_filter_destroy(self.as_mut_ptr()) };
}
}
*/
11 changes: 4 additions & 7 deletions src/ndb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,9 @@ mod tests {
{
let ndb = Ndb::new(db, &Config::new()).expect("ndb");

let mut filter = Filter::new();
filter.kinds(vec![1]);

let filter = Filter::new().kinds(vec![1]).build();
let filters = vec![filter];

let sub = ndb.subscribe(filters.clone()).expect("sub_id");
let waiter = ndb.wait_for_notes(&sub, 1);
ndb.process_event(r#"["EVENT","b",{"id": "702555e52e82cc24ad517ba78c21879f6e47a7c0692b9b20df147916ae8731a3","pubkey": "32bf915904bfde2d136ba45dde32c88f4aca863783999faea2e847a8fafd2f15","created_at": 1702675561,"kind": 1,"tags": [],"content": "hello, world","sig": "2275c5f5417abfd644b7bc74f0388d70feb5d08b6f90fa18655dda5c95d013bfbc5258ea77c05b7e40e0ee51d8a2efa931dc7a0ec1db4c0a94519762c6625675"}]"#).expect("process ok");
Expand All @@ -355,8 +354,7 @@ mod tests {
{
let ndb = Ndb::new(db, &Config::new()).expect("ndb");

let mut filter = Filter::new();
filter.kinds(vec![1]);
let filter = Filter::new().kinds(vec![1]).build();

let sub = ndb.subscribe(vec![filter]).expect("sub_id");
let waiter = ndb.wait_for_notes(&sub, 1);
Expand All @@ -374,8 +372,7 @@ mod tests {
{
let ndb = Ndb::new(db, &Config::new()).expect("ndb");

let mut filter = Filter::new();
filter.kinds(vec![1]);
let filter = Filter::new().kinds(vec![1]).build();

let sub = ndb.subscribe(vec![filter]).expect("sub_id");
ndb.process_event(r#"["EVENT","b",{"id": "702555e52e82cc24ad517ba78c21879f6e47a7c0692b9b20df147916ae8731a3","pubkey": "32bf915904bfde2d136ba45dde32c88f4aca863783999faea2e847a8fafd2f15","created_at": 1702675561,"kind": 1,"tags": [],"content": "hello, world","sig": "2275c5f5417abfd644b7bc74f0388d70feb5d08b6f90fa18655dda5c95d013bfbc5258ea77c05b7e40e0ee51d8a2efa931dc7a0ec1db4c0a94519762c6625675"}]"#).expect("process ok");
Expand Down

0 comments on commit 1d65de2

Please sign in to comment.