Uploaded image for project: 'C Driver'
  1. C Driver
  2. CDRIVER-3685

Single-threaded mongoc_client_t in separate threads may write to the global handshake "frozen" boolean

    • Type: Icon: Bug Bug
    • Resolution: Fixed
    • Priority: Icon: Major - P3 Major - P3
    • 1.28.0, 1.27.6
    • Affects Version/s: None
    • Component/s: Testing
    • None
    • Not Needed
    • Hide

      1. What would you like to communicate to the user about this feature?
      2. Would you like the user to see examples of the syntax and/or executable code and its output?
      3. Which versions of the driver/connector does this apply to?

      Show
      1. What would you like to communicate to the user about this feature? 2. Would you like the user to see examples of the syntax and/or executable code and its output? 3. Which versions of the driver/connector does this apply to?

      Discovered when investigatingĀ CDRIVER-3674. TSan reports a data race when creating multiple threads with single-threaded mongoc_client_t. Here is an example:

      #include <mongoc/mongoc.h>
      #include <stdio.h>
      #include <stdlib.h>
      #include <pthread.h>
      
      void * threadfn (void* data) {
         bson_error_t error;
         mongoc_client_t *client = mongoc_client_new ("mongodb://localhost:27018 ");
         mongoc_collection_t *coll = mongoc_client_get_collection (client, "test", "test");
         bson_t *doc = bson_new();
         if (!mongoc_collection_insert_one (coll, doc, NULL, NULL, &error)) {
            printf ("thread: %s\n", error.message);
         }
         return NULL;
      }
      
      int
      main (int argc, char *argv[])
      {
         pthread_t threads[100];
         int i;
      
         mongoc_init ();
         for (i = 0; i < 100; i++) {
            pthread_create (threads + i, NULL, threadfn, NULL);
         }
         for (i = 0; i < 100; i++) {
            pthread_join (threads[i], NULL);
         }
         mongoc_cleanup();
      }
      

      Running with TSan shows this warning:

      ==================
      WARNING: ThreadSanitizer: data race (pid=31598)
        Write of size 1 at 0x00010e16a128 by thread T4:
          #0 _mongoc_handshake_freeze mongoc-handshake.c:565 (libmongoc-1.0.0.dylib:x86_64+0x6560b)
          #1 _mongoc_topology_do_blocking_scan mongoc-topology.c:643 (libmongoc-1.0.0.dylib:x86_64+0xa3c68)
          #2 mongoc_topology_select_server_id mongoc-topology.c:879 (libmongoc-1.0.0.dylib:x86_64+0xa46fa)
          #3 _mongoc_cluster_select_server_id mongoc-cluster.c:2236 (libmongoc-1.0.0.dylib:x86_64+0x301ae)
          #4 _mongoc_cluster_stream_for_optype mongoc-cluster.c:2282 (libmongoc-1.0.0.dylib:x86_64+0x2a5ac)
          #5 mongoc_cluster_stream_for_writes mongoc-cluster.c:2368 (libmongoc-1.0.0.dylib:x86_64+0x2a6e7)
          #6 _mongoc_collection_write_command_execute_idl mongoc-collection.c:94 (libmongoc-1.0.0.dylib:x86_64+0x383e6)
          #7 mongoc_collection_insert_one mongoc-collection.c:1639 (libmongoc-1.0.0.dylib:x86_64+0x381c7)
          #8 threadfn example-client.c:16 (example-client:x86_64+0x100003ab4)
      
        Previous write of size 1 at 0x00010e16a128 by thread T2:
          #0 _mongoc_handshake_freeze mongoc-handshake.c:565 (libmongoc-1.0.0.dylib:x86_64+0x6560b)
          #1 _mongoc_topology_do_blocking_scan mongoc-topology.c:643 (libmongoc-1.0.0.dylib:x86_64+0xa3c68)
          #2 mongoc_topology_select_server_id mongoc-topology.c:879 (libmongoc-1.0.0.dylib:x86_64+0xa46fa)
          #3 _mongoc_cluster_select_server_id mongoc-cluster.c:2236 (libmongoc-1.0.0.dylib:x86_64+0x301ae)
          #4 _mongoc_cluster_stream_for_optype mongoc-cluster.c:2282 (libmongoc-1.0.0.dylib:x86_64+0x2a5ac)
          #5 mongoc_cluster_stream_for_writes mongoc-cluster.c:2368 (libmongoc-1.0.0.dylib:x86_64+0x2a6e7)
          #6 _mongoc_collection_write_command_execute_idl mongoc-collection.c:94 (libmongoc-1.0.0.dylib:x86_64+0x383e6)
          #7 mongoc_collection_insert_one mongoc-collection.c:1639 (libmongoc-1.0.0.dylib:x86_64+0x381c7)
          #8 threadfn example-client.c:16 (example-client:x86_64+0x100003ab4)
      
        Location is global 'gMongocHandshake' at 0x00010e16a0e0 (libmongoc-1.0.0.dylib+0x0000000ef128)
      
        Thread T4 (tid=13837519, running) created by main thread at:
          #0 pthread_create <null>:2668928 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x2aced)
          #1 main example-client.c:37 (example-client:x86_64+0x100003be9)
      
        Thread T2 (tid=13837517, finished) created by main thread at:
          #0 pthread_create <null>:2668928 (libclang_rt.tsan_osx_dynamic.dylib:x86_64h+0x2aced)
          #1 main example-client.c:37 (example-client:x86_64+0x100003be9)
      

      I suspect it is unlikely this would amount to any observable bug, since both threads are writing "true" to frozen. And once the handshake is frozen it remains frozen indefinitely. But this is a signal that we may not have test coverage for multiple single threaded clients being used in multiple threads.

            Assignee:
            ezra.chung@mongodb.com Ezra Chung
            Reporter:
            kevin.albertson@mongodb.com Kevin Albertson
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: