Skip to content

Commit 973acb2

Browse files
authored
SWIFT-779 Safe access to ReadPreference pointer (#456)
1 parent 940d90d commit 973acb2

23 files changed

+322
-226
lines changed

Package.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ let package = Package(
1616
.target(name: "AtlasConnectivity", dependencies: ["MongoSwiftSync"]),
1717
.target(name: "TestsCommon", dependencies: ["MongoSwift", "Nimble"]),
1818
.testTarget(name: "BSONTests", dependencies: ["MongoSwift", "TestsCommon", "Nimble", "CLibMongoC"]),
19-
.testTarget(name: "MongoSwiftTests", dependencies: ["MongoSwift", "TestsCommon", "Nimble", "NIO", "CLibMongoC"]),
19+
.testTarget(name: "MongoSwiftTests", dependencies: ["MongoSwift", "TestsCommon", "Nimble", "NIO"]),
2020
.testTarget(name: "MongoSwiftSyncTests", dependencies: ["MongoSwiftSync", "TestsCommon", "Nimble", "MongoSwift"]),
2121
.target(
2222
name: "CLibMongoC",

Sources/MongoSwift/ConnectionPool.swift

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,19 @@ internal class ConnectionPool {
160160
/// started already. This method may block.
161161
internal func selectServer(forWrites: Bool, readPreference: ReadPreference? = nil) throws -> ServerDescription {
162162
try self.withConnection { conn in
163-
var error = bson_error_t()
164-
guard let desc = mongoc_client_select_server(
165-
conn.clientHandle,
166-
forWrites,
167-
readPreference?.pointer,
168-
&error
169-
) else {
170-
throw extractMongoError(error: error)
163+
try ReadPreference.withOptionalMongocReadPreference(from: readPreference) { rpPtr in
164+
var error = bson_error_t()
165+
guard let desc = mongoc_client_select_server(
166+
conn.clientHandle,
167+
forWrites,
168+
rpPtr,
169+
&error
170+
) else {
171+
throw extractMongoError(error: error)
172+
}
173+
defer { mongoc_server_description_destroy(desc) }
174+
return ServerDescription(desc)
171175
}
172-
173-
defer { mongoc_server_description_destroy(desc) }
174-
return ServerDescription(desc)
175176
}
176177
}
177178

Sources/MongoSwift/ConnectionString.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ internal class ConnectionString {
4747
/// The `ReadConcern` for this connection string.
4848
internal var readConcern: ReadConcern {
4949
get {
50-
ReadConcern(from: mongoc_uri_get_read_concern(self._uri))
50+
ReadConcern(copying: mongoc_uri_get_read_concern(self._uri))
5151
}
5252
set(rc) {
5353
rc.withMongocReadConcern { rcPtr in
@@ -59,7 +59,7 @@ internal class ConnectionString {
5959
/// The `WriteConcern` for this connection string.
6060
internal var writeConcern: WriteConcern {
6161
get {
62-
WriteConcern(from: mongoc_uri_get_write_concern(self._uri))
62+
WriteConcern(copying: mongoc_uri_get_write_concern(self._uri))
6363
}
6464
set(wc) {
6565
wc.withMongocWriteConcern { wcPtr in
@@ -74,7 +74,9 @@ internal class ConnectionString {
7474
ReadPreference(copying: mongoc_uri_get_read_prefs_t(self._uri))
7575
}
7676
set(rp) {
77-
mongoc_uri_set_read_prefs_t(self._uri, rp.pointer)
77+
rp.withMongocReadPreference { rpPtr in
78+
mongoc_uri_set_read_prefs_t(self._uri, rpPtr)
79+
}
7880
}
7981
}
8082

Sources/MongoSwift/MongoClient.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import CLibMongoC
12
import Foundation
23
import NIO
34
import NIOConcurrencyHelpers
@@ -609,6 +610,30 @@ public class MongoClient {
609610
) throws -> T.OperationResult {
610611
try self.operationExecutor.execute(operation, using: connection, client: self, session: session).wait()
611612
}
613+
614+
/// Internal method to check the `ReadConcern` that was ultimately set on this client. **This method may block
615+
/// and is for testing purposes only**.
616+
internal func getMongocReadConcern() throws -> ReadConcern? {
617+
try self.connectionPool.withConnection { conn in
618+
ReadConcern(copying: mongoc_client_get_read_concern(conn.clientHandle))
619+
}
620+
}
621+
622+
/// Internal method to check the `ReadPreference` that was ultimately set on this client. **This method may block
623+
/// and is for testing purposes only**.
624+
internal func getMongocReadPreference() throws -> ReadPreference {
625+
try self.connectionPool.withConnection { conn in
626+
ReadPreference(copying: mongoc_client_get_read_prefs(conn.clientHandle))
627+
}
628+
}
629+
630+
/// Internal method to check the `WriteConcern` that was ultimately set on this client. **This method may block
631+
/// and is for testing purposes only**.
632+
internal func getMongocWriteConcern() throws -> WriteConcern? {
633+
try self.connectionPool.withConnection { conn in
634+
WriteConcern(copying: mongoc_client_get_write_concern(conn.clientHandle))
635+
}
636+
}
612637
}
613638

614639
extension MongoClient: Equatable {

Sources/MongoSwift/MongoCollection+BulkWrite.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ internal struct BulkWriteOperation<T: Codable>: Operation {
257257
// transactions do not support unacknowledged writes.
258258
writeConcernAcknowledged = true
259259
} else {
260-
let writeConcern = WriteConcern(from: mongoc_bulk_operation_get_write_concern(bulk))
260+
let writeConcern = WriteConcern(copying: mongoc_bulk_operation_get_write_concern(bulk))
261261
writeConcernAcknowledged = writeConcern.isAcknowledged
262262
}
263263

Sources/MongoSwift/MongoCollection.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,41 @@ public struct MongoCollection<T: Codable> {
139139

140140
if self.readPreference != self._client.readPreference {
141141
// there is no concept of an empty read preference so we will always have a value here.
142-
mongoc_collection_set_read_prefs(collection, self.readPreference.pointer)
142+
self.readPreference.withMongocReadPreference { rpPtr in
143+
mongoc_collection_set_read_prefs(collection, rpPtr)
144+
}
143145
}
144146

145147
return try body(collection)
146148
}
149+
150+
/// Internal method to check the `ReadConcern` that is set on `mongoc_collection_t`s via `withMongocCollection`.
151+
/// **This method may block and is for testing purposes only**.
152+
internal func getMongocReadConcern() throws -> ReadConcern? {
153+
try self._client.connectionPool.withConnection { conn in
154+
self.withMongocCollection(from: conn) { collPtr in
155+
ReadConcern(copying: mongoc_collection_get_read_concern(collPtr))
156+
}
157+
}
158+
}
159+
160+
/// Internal method to check the `ReadPreference` that is set on `mongoc_collection_t`s via `withMongocCollection`.
161+
/// **This method may block and is for testing purposes only**.
162+
internal func getMongocReadPreference() throws -> ReadPreference {
163+
try self._client.connectionPool.withConnection { conn in
164+
self.withMongocCollection(from: conn) { collPtr in
165+
ReadPreference(copying: mongoc_collection_get_read_prefs(collPtr))
166+
}
167+
}
168+
}
169+
170+
/// Internal method to check the `WriteConcern` that is set on `mongoc_collection_t`s via `withMongocCollection`.
171+
/// **This method may block and is for testing purposes only**.
172+
internal func getMongocWriteConcern() throws -> WriteConcern? {
173+
try self._client.connectionPool.withConnection { conn in
174+
self.withMongocCollection(from: conn) { collPtr in
175+
WriteConcern(copying: mongoc_collection_get_write_concern(collPtr))
176+
}
177+
}
178+
}
147179
}

Sources/MongoSwift/MongoDatabase.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,9 +491,41 @@ public struct MongoDatabase {
491491

492492
if self.readPreference != self._client.readPreference {
493493
// there is no concept of an empty read preference so we will always have a value here.
494-
mongoc_database_set_read_prefs(db, self.readPreference.pointer)
494+
self.readPreference.withMongocReadPreference { rpPtr in
495+
mongoc_database_set_read_prefs(db, rpPtr)
496+
}
495497
}
496498

497499
return try body(db)
498500
}
501+
502+
/// Internal method to check the `ReadConcern` that is set on `mongoc_database_t`s via `withMongocDatabase`.
503+
/// **This method may block and is for testing purposes only**.
504+
internal func getMongocReadConcern() throws -> ReadConcern? {
505+
try self._client.connectionPool.withConnection { conn in
506+
self.withMongocDatabase(from: conn) { dbPtr in
507+
ReadConcern(copying: mongoc_database_get_read_concern(dbPtr))
508+
}
509+
}
510+
}
511+
512+
/// Internal method to check the `ReadPreference` that is set on `mongoc_database_t`s via `withMongocDatabase`.
513+
/// **This method may block and is for testing purposes only**.
514+
internal func getMongocReadPreference() throws -> ReadPreference {
515+
try self._client.connectionPool.withConnection { conn in
516+
self.withMongocDatabase(from: conn) { dbPtr in
517+
ReadPreference(copying: mongoc_database_get_read_prefs(dbPtr))
518+
}
519+
}
520+
}
521+
522+
/// Internal method to check the `WriteConcern` that is set on `mongoc_database_t`s via `withMongocDatabase`.
523+
/// **This method may block and is for testing purposes only**.
524+
internal func getMongocWriteConcern() throws -> WriteConcern? {
525+
try self._client.connectionPool.withConnection { conn in
526+
self.withMongocDatabase(from: conn) { dbPtr in
527+
WriteConcern(copying: mongoc_database_get_write_concern(dbPtr))
528+
}
529+
}
530+
}
499531
}

Sources/MongoSwift/Operations/AggregateOperation.swift

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,23 @@ internal struct AggregateOperation<CollectionType: Codable>: Operation {
8383

8484
internal func execute(using connection: Connection, session: ClientSession?) throws -> MongoCursor<Document> {
8585
let opts = try encodeOptions(options: self.options, session: session)
86-
let rp = self.options?.readPreference?.pointer
8786
let pipeline: Document = ["pipeline": .array(self.pipeline.map { .document($0) })]
8887

8988
let result: OpaquePointer = self.collection.withMongocCollection(from: connection) { collPtr in
9089
pipeline.withBSONPointer { pipelinePtr in
9190
withOptionalBSONPointer(to: opts) { optsPtr in
92-
guard let result = mongoc_collection_aggregate(
93-
collPtr,
94-
MONGOC_QUERY_NONE,
95-
pipelinePtr,
96-
optsPtr,
97-
rp
98-
) else {
99-
fatalError(failedToRetrieveCursorMessage)
91+
ReadPreference.withOptionalMongocReadPreference(from: self.options?.readPreference) { rpPtr in
92+
guard let result = mongoc_collection_aggregate(
93+
collPtr,
94+
MONGOC_QUERY_NONE,
95+
pipelinePtr,
96+
optsPtr,
97+
rpPtr
98+
) else {
99+
fatalError(failedToRetrieveCursorMessage)
100+
}
101+
return result
100102
}
101-
return result
102103
}
103104
}
104105
}

Sources/MongoSwift/Operations/CountDocumentsOperation.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,13 @@ internal struct CountDocumentsOperation<T: Codable>: Operation {
6363

6464
internal func execute(using connection: Connection, session: ClientSession?) throws -> Int {
6565
let opts = try encodeOptions(options: options, session: session)
66-
let rp = self.options?.readPreference?.pointer
6766
var error = bson_error_t()
6867
let count = self.collection.withMongocCollection(from: connection) { collPtr in
6968
self.filter.withBSONPointer { filterPtr in
7069
withOptionalBSONPointer(to: opts) { optsPtr in
71-
mongoc_collection_count_documents(collPtr, filterPtr, optsPtr, rp, nil, &error)
70+
ReadPreference.withOptionalMongocReadPreference(from: self.options?.readPreference) { rpPtr in
71+
mongoc_collection_count_documents(collPtr, filterPtr, optsPtr, rpPtr, nil, &error)
72+
}
7273
}
7374
}
7475
}

Sources/MongoSwift/Operations/DistinctOperation.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,15 @@ internal struct DistinctOperation<T: Codable>: Operation {
5656
]
5757

5858
let opts = try encodeOptions(options: self.options, session: session)
59-
let rp = self.options?.readPreference?.pointer
6059
var reply = Document()
6160
var error = bson_error_t()
6261
let success = self.collection.withMongocCollection(from: connection) { collPtr in
6362
command.withBSONPointer { cmdPtr in
64-
withOptionalBSONPointer(to: opts) { optsPtr in
65-
reply.withMutableBSONPointer { replyPtr in
66-
mongoc_collection_read_command_with_opts(collPtr, cmdPtr, rp, optsPtr, replyPtr, &error)
63+
ReadPreference.withOptionalMongocReadPreference(from: self.options?.readPreference) { rpPtr in
64+
withOptionalBSONPointer(to: opts) { optsPtr in
65+
reply.withMutableBSONPointer { replyPtr in
66+
mongoc_collection_read_command_with_opts(collPtr, cmdPtr, rpPtr, optsPtr, replyPtr, &error)
67+
}
6768
}
6869
}
6970
}

0 commit comments

Comments
 (0)