SQLite Forum

DATA RACE 2: Found in sqlite3.c

DATA RACE 2: Found in sqlite3.c

(1) By Zu-Ming Jiang (jiang446079653) on 2020-04-29 03:32:30

Dear SQLite developers:

I used my fuzz-testing tool, connzer, to detect data race in SQLite. Here is a data race found by connzer. I wish you can help me check whether it is a real race, thanks!!

The following is the race report.

## Race report ##

**Version:** 3.30.1

**Race object:** `pShmNode->pShmMutex`

**Thread 1:**

**Access:** `pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);`

**Line number:** `sqlite3.c, 37258`

**Call stack:**

1. `unixOpenSharedMemory()`
2. `unixShmMap()`
3. `sqlite3OsShmMap()`
4. `walIndexPageRealloc()`
5. `walIndexPage()`
6. `walIndexReadHdr()`
7. `walTryBeginRead()`
8. `sqlite3WalBeginReadTransaction()`
9. `pagerBeginReadTransaction()`
10. `sqlite3PagerSharedLock()`
11. `lockBtree()`
12. `sqlite3BtreeBeginTrans()`
13. `sqlite3VdbeExec()`
14. `sqlite3Step()`
15. `sqlite3_step()`
16. `sqlite3_exec()`
17. `sql_script_x()`
18. `walthread2_thread()`
19. `launch_thread_main()`

**Lock:** `unixEnterMutex()`

**Thread 2:**

**Access:** `sqlite3_mutex_enter(pShmNode->pShmMutex);`

**Line number:** `sqlite3.c; 37305`

**Call stack:**

0. `unixOpenSharedMemory()`
1. `unixShmMap()`
2. `sqlite3OsShmMap()`
3. `walIndexPageRealloc()`
4. `walIndexPage()`
5. `walIndexReadHdr()`
6. `walTryBeginRead()`
7. `sqlite3WalBeginReadTransaction()`
8. `pagerBeginReadTransaction()`
9. `sqlite3PagerSharedLock()`
10. `lockBtree()`
11. `sqlite3BtreeBeginTrans()`
12. `sqlite3BtreeSetVersion()`
13. `sqlite3VdbeExec()`
14. `sqlite3Step()`
15. `sqlite3_step()`
16. `sqlite3_exec()`
17. `sql_script_x()`
18. `walthread2_thread()`
19. `launch_thread_main()`

**Lock:** `sqlite3_mutex_enter(pShmNode->pShmMutex)`

**Impact:** This race may cause serious consequence: if the race access in thread 2 is executed before the race access in thread 1,  `pShmNode->pShmMutex` in `unixOpenSharedMemory()` in thread 2 will be uninitialized, and `sqlite3_mutex_enter(pShmNode->pShmMutex)` will cause crash.

My fuzzer finds that these 2 accesses can be executed concurrently, and they are protected by different locks, so my fuzzer report this race.

(2) By Zu-Ming Jiang (jiang446079653) on 2020-05-02 07:29:53 in reply to 1 [link]

What do you think about this data race?

(3) By Richard Hipp (drh) on 2020-05-02 11:24:17 in reply to 2 [link]

Your analysis is incorrect.

This is no code path that reaches line sqlite3.c:37305 
with pShmNode->pShmMutex uninitialized in a thread-safe
build.  Every path to sqlite3.c:37305 must traverse this code:

  pInode = pDbFd->pInode;
  pShmNode = pInode->pShmNode;
  if( pShmNode==0 ){
    if( sqlite3GlobalConfig.bCoreMutex ){
      pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST);

Assuming the `sqlite3GlobalConfig.bCoreMutex` global variable is true,
that means that `pShmNode->pShmMutex` must be initialized prior to use.

Your tool is perhaps confused because it assumes that
`sqlite3GlobalConfig.bCoreMutex` might be false.  But that is only
true if SQLite is running in "[single-threaded mode][1]".

I suppose your tool is technically correct - there is a data race
if you have configured SQLite for single-threaded mode.  But that
does not really count, since the documentation clearly states that
in single-threaded mode, SQLite is not threadsafe.

[1]: https://www.sqlite.org/threadsafe.html

(4) By Zu-Ming Jiang (jiang446079653) on 2020-05-03 02:00:03 in reply to 3 [link]

Yes, you are right.

Thanks for your response!!