Skip to content

Guard last_event_id() against the async event loop in SSEClient - #2644

Merged
yhirose merged 2 commits into
yhirose:masterfrom
metsw24-max:sse-last-event-id-lock
Oct 26, 2026
Merged

yhirose merged 2 commits into
yhirose:masterfrom
metsw24-max:sse-last-event-id-lock

Conversation

@metsw24-max

Copy link
Copy Markdown
Contributor

Unsynchronised read of last_event_id() in SSEClient

run_event_loop() assigns last_event_id_ from every event with an id: field, and under start_async() that loop runs on its own thread. last_event_id() handed back a reference to the same string without a lock, so an application reading it from its own thread (the README lists it next to the atomic is_connected()) races writes the server controls. I've guarded the member with a mutex and made the getter return a copy.

Reviewer notes

  • ThreadSanitizer reports the race against the current header (std::string::_M_assign in the event loop vs. the caller's copy). The new SSEIntegrationTest.LastEventIdWhileRunning fails under -fsanitize=thread before the change and passes after; the SSE tests also pass under the usual ASan build.
  • The return type changes from const std::string & to std::string. std::string id = sse.last_event_id(); and stream insertion still compile unchanged, and I've updated the README snippet, but this may be worth flagging as a small API change.

metsw24-max and others added 2 commits October 25, 2026 15:27
SSEClient::last_event_id() returned a reference to last_event_id_ with no
lock, while run_event_loop() assigns it from each event that carries an id.
Under start_async() the loop runs on its own thread, so reading the id from
the application's thread raced the writes the server drives. The id is now
stored and read under a mutex, and last_event_id() returns a copy.
@yhirose
yhirose merged commit 2f8b9f6 into yhirose:master Oct 26, 2026
27 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants