Skip to content

Commit 555e5bb

Browse files
authored
Fix NULL pointer handling in conflict resolver (#81)
According to [the documentation](https://docs.couchbase.com/mobile/3.2.4/couchbase-lite-c/C/html/group__documents.html#ga6f9eaf3d038f8359b9d9fd3badc51be7) the second parameter (the remote document) can be NULL if the document is deleted in central. Wrapping a NULL pointer in a `Document` instance can lead to undefined behavior or crashes, so the `ConflictHandler` function now uses an Option for its second parameter.
1 parent f89b4f6 commit 555e5bb

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

src/document.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ pub enum ConcurrencyControl {
6565
/// if the save would cause a conflict, i.e. if the document in the database has been updated
6666
/// (probably by a pull replicator, or by application code on another thread)
6767
/// since it was loaded into the CBLDocument being saved.
68-
type ConflictHandler = fn(&mut Document, &Document) -> bool;
68+
/// Return true to save the document, false to cancel the save.
69+
type ConflictHandler = fn(&mut Document, Option<&Document>) -> bool;
6970
#[unsafe(no_mangle)]
7071
unsafe extern "C" fn c_conflict_handler(
7172
context: *mut ::std::os::raw::c_void,
@@ -74,10 +75,15 @@ unsafe extern "C" fn c_conflict_handler(
7475
) -> bool {
7576
unsafe {
7677
let callback: ConflictHandler = std::mem::transmute(context);
78+
let remote_document = &Document::reference(conflicting_document as *mut CBLDocument);
7779

7880
callback(
7981
&mut Document::reference(document_being_saved),
80-
&Document::reference(conflicting_document as *mut CBLDocument),
82+
if conflicting_document.is_null() {
83+
None
84+
} else {
85+
Some(remote_document)
86+
},
8187
)
8288
}
8389
}

tests/document_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ fn database_save_document_resolving() {
206206
document = default_collection(db)
207207
.save_document_resolving(&mut document, |document_a, document_b| {
208208
let property_a = document_a.properties().get("foo").as_i64_or_0();
209-
let property_b = document_b.properties().get("foo").as_i64_or_0();
209+
let property_b = document_b.unwrap().properties().get("foo").as_i64_or_0();
210210
document_a
211211
.mutable_properties()
212212
.at("foo")

0 commit comments

Comments
 (0)