Skip to content

readIndex in RedisCache is not atomic — data race between writeBuffer and copyReadBuffer #86

Description

@bigsamich

Description

In RedisCache.hpp:26, readIndex is a plain int. It is written under the exclusive lock in writeBuffer (line 41), but read outside any lock on line 34:

void writeBuffer(...)
{
    int writeIndex = (readIndex + 1) % 2;  // line 34 — READ outside lock
    buffers.at(writeIndex) = data;
    {
        std::lock_guard<std::shared_mutex> swapLock(swapMutex);
        readIndex = (readIndex + 1) % 2;   // line 41 — WRITE under lock
    }
}

If writeBuffer is called from the reader callback thread while another thread holds the shared lock for reading, the read on line 34 races with the write on line 41.

Severity

Medium

Suggested Fix

Make readIndex an std::atomic<int>, or access it under the mutex consistently.

Activity

  1. bigsamich commented on Sep 30, 2026

    @bigsamich
    ContributorAuthor

    The race described here can't actually happen:

    • writeBuffer runs only from this cache's reader callback;
    • ThreadPool::job pins each stream key to one worker (hasher(name) % num);
    • so lines 34 and 41 always run on the same thread.

    TSan reports nothing at those lines, on main or at the #111 stack head.

    The race TSan does find in RedisCache is copyReadBuffer filling the cache while holding only the shared lock. Concurrent readers then write lastWrite and assign into the same buffer vector, including during reallocation. I've filed that as #120; this issue could be re-scoped or closed in favour of it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions