Skip to content

Commit b9e8cba

Browse files
authored
SWIFT-969 Manually clean up mongoc_uri_t when options validation fails (#520)
1 parent e3de6ae commit b9e8cba

File tree

2 files changed

+33
-13
lines changed

2 files changed

+33
-13
lines changed

Sources/MongoSwift/ConnectionString.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import CLibMongoC
44
internal class ConnectionString {
55
/// Pointer to the underlying `mongoc_uri_t`.
66
private let _uri: OpaquePointer
7+
/// Tracks whether we have already destroyed the above pointer.
8+
private var destroyedPtr = false
79

810
/// Initializes a new `ConnectionString` with the provided options.
911
internal init(_ connectionString: String, options: MongoClientOptions? = nil) throws {
@@ -13,7 +15,16 @@ internal class ConnectionString {
1315
}
1416
self._uri = uri
1517

16-
try self.applyAndValidateOptions(options)
18+
// Due to SR-13355, deinit does not get called if we throw here. If we encounter an error, we need to manually
19+
// clean up the pointer. We use a variable to track whether we already destroyed it so that, in the event the
20+
// bug is fixed and `deinit` starts being called, we don't start calling `mongoc_uri_destroy` twice.
21+
do {
22+
try self.applyAndValidateOptions(options)
23+
} catch {
24+
mongoc_uri_destroy(self._uri)
25+
self.destroyedPtr = true
26+
throw error
27+
}
1728
}
1829

1930
private func applyAndValidateOptions(_ options: MongoClientOptions?) throws {
@@ -361,7 +372,9 @@ internal class ConnectionString {
361372

362373
/// Cleans up the underlying `mongoc_uri_t`.
363374
deinit {
364-
mongoc_uri_destroy(self._uri)
375+
if !self.destroyedPtr {
376+
mongoc_uri_destroy(self._uri)
377+
}
365378
}
366379

367380
private var usesDNSSeedlistFormat: Bool {

Sources/MongoSwift/Operations/CountDocumentsOperation.swift

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,28 @@ internal struct CountDocumentsOperation<T: Codable>: Operation {
6464
internal func execute(using connection: Connection, session: ClientSession?) throws -> Int {
6565
let opts = try encodeOptions(options: options, session: session)
6666
var error = bson_error_t()
67-
var reply = BSONDocument()
68-
let count = self.collection.withMongocCollection(from: connection) { collPtr in
69-
self.filter.withBSONPointer { filterPtr in
70-
withOptionalBSONPointer(to: opts) { optsPtr in
71-
ReadPreference.withOptionalMongocReadPreference(from: self.options?.readPreference) { rpPtr in
72-
reply.withMutableBSONPointer { replyPtr in
73-
mongoc_collection_count_documents(collPtr, filterPtr, optsPtr, rpPtr, replyPtr, &error)
67+
68+
return try self.collection.withMongocCollection(from: connection) { collPtr in
69+
try self.filter.withBSONPointer { filterPtr in
70+
try withOptionalBSONPointer(to: opts) { optsPtr in
71+
try ReadPreference.withOptionalMongocReadPreference(from: self.options?.readPreference) { rpPtr in
72+
try withStackAllocatedMutableBSONPointer { replyPtr in
73+
let count = mongoc_collection_count_documents(
74+
collPtr,
75+
filterPtr,
76+
optsPtr,
77+
rpPtr,
78+
replyPtr,
79+
&error
80+
)
81+
guard count != -1 else {
82+
throw extractMongoError(error: error, reply: BSONDocument(copying: replyPtr))
83+
}
84+
return Int(count)
7485
}
7586
}
7687
}
7788
}
7889
}
79-
80-
guard count != -1 else { throw extractMongoError(error: error, reply: reply) }
81-
82-
return Int(count)
8390
}
8491
}

0 commit comments

Comments
 (0)