SQLite Forum

ThreadSantizer warning for sqlite3_enable_shared_cache()
Login
I'm running into a warning from ThreadSanitizer while using `sqlite3_enable_shared_cache()` between two threads. I've minimized it down to a simple test program below, followed by the back trace from TSan.

```
#include <chrono>
#include <thread>
#include <sqlite3.h>

namespace {

void Init() {
	sqlite3_enable_shared_cache(1);
	std::this_thread::sleep_for(std::chrono::seconds(2));
}

}  // namespace

int main(int argc, char* argv[]) {
	std::thread t1(&Init);
	std::thread t2(&Init);
	t1.join();
	t2.join();

	return 0;
}
```

With that file in `test.cc` and `sqlite3.{h,c}` in the same directory, I'm building with:

```
clang-11 -fsanitize=thread -g -c sqlite3.c
clang-11 -std=c++17 -stdlib=libstdc++ -fsanitize=thread -g -I. -c test.cc
clang -lstdc++ -std=c++17 -fsanitize=thread *.o -o warn_test
```

Running `warn_test` results in this report from TSan:

```
==================
WARNING: ThreadSanitizer: data race (pid=123110)
  Write of size 4 at 0x000000706dac by thread T2:
    #0 sqlite3_enable_shared_cache /home/tim/test/sqlite3.c:65571:3 (race+0x4c3d8a)
    #1 (anonymous namespace)::Init() /home/tim/test/test.cc:12:2 (race+0x6a35ea)
    #2 void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/invoke.h:60:14 (race+0x6a49ed)
    #3 std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/invoke.h:95:14 (race+0x6a48f0)
    #4 void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:244:13 (race+0x6a4898)
    #5 std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:251:11 (race+0x6a4838)
    #6 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:195:13 (race+0x6a461f)
    #7 <null> <null> (libstdc++.so.6+0xd6de3)

  Previous write of size 4 at 0x000000706dac by thread T1:
    #0 sqlite3_enable_shared_cache /home/tim/test/sqlite3.c:65571:3 (race+0x4c3d8a)
    #1 (anonymous namespace)::Init() /home/tim/test/test.cc:12:2 (race+0x6a35ea)
    #2 void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/invoke.h:60:14 (race+0x6a49ed)
    #3 std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/bits/invoke.h:95:14 (race+0x6a48f0)
    #4 void std::thread::_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:244:13 (race+0x6a4898)
    #5 std::thread::_Invoker<std::tuple<void (*)()> >::operator()() /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:251:11 (race+0x6a4838)
    #6 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/bin/../lib/gcc/x86_64-linux-gnu/9/../../../../include/c++/9/thread:195:13 (race+0x6a461f)
    #7 <null> <null> (libstdc++.so.6+0xd6de3)

  Location is global 'sqlite3Config' of size 424 at 0x000000706c60 (race+0x000000706dac)

  Thread T2 (tid=123113, running) created by main thread at:
    #0 pthread_create <null> (race+0x425ccb)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 main /home/tim/test/test.cc:20:14 (race+0x6a34d1)

  Thread T1 (tid=123112, running) created by main thread at:
    #0 pthread_create <null> (race+0x425ccb)
    #1 std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) <null> (libstdc++.so.6+0xd70a8)
    #2 main /home/tim/test/test.cc:19:14 (race+0x6a34a7)

SUMMARY: ThreadSanitizer: data race /home/tim/test/sqlite3.c:65571:3 in sqlite3_enable_shared_cache
==================
ThreadSanitizer: reported 1 warnings
```

I'm able to fix it by changing `sqlite3GlobalConfig.sharedCacheEnabled` to be an `atomic_int` and #include'ing `<stdatomic.h>` but I understand that's a C11 feature and may not be acceptable. I did try to fix it using `AtomicLoad()` and `AtomicStore()` but for some reason I was getting the same warning from TSan.