Skip to content

ZOOKEEPER-5126: (C client) Async watch removals corrupt context and report false success - #2501

Open
apurtell wants to merge 2 commits into
apache:masterfrom
apurtell:ZOOKEEPER-5126
Open

apurtell wants to merge 2 commits into
apache:masterfrom
apurtell:ZOOKEEPER-5126

Conversation

@apurtell

@apurtell apurtell commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

Fix a group of related defects in the C client watch removal APIs:

  • In the multithreaded library, a local removal with zoo_aremove_watches() or zoo_aremove_all_watches() cast the caller's data pointer to a sync completion and signaled it. This writes mutex state into application memory and can hang in pthread_mutex_lock. After the fix aremove_watches() no longer signals a sync completion. A local removal is complete when the call returns, so the synchronous wrapper waits only for removals that go to the server. A local removal does not call the completion, as before. The header documents these semantics.
  • zoo_aremove_watches() and zoo_aremove_all_watches() declared the completion as void_completion_t *, a pointer to a function pointer. Correct callers failed to compile in C++ and with GCC 14. The fix declare its as void_completion_t. The ABI does not change.
  • containsWatcher() matched a NULL watcher before it looked up the path. A local removal of all watches returned ZOK for a path with no watches. The fix is to return ZNOWATCHER, as the header mentions and as the Java client does.

Adds the test Zookeeper_simpleSystem::testAsyncRemoveWatchers.

Andrew Purtell and others added 2 commits November 6, 2026 23:43
…eport false success

Fix a group of related defects in the C client watch removal APIs:

- In the multithreaded library, a local removal with zoo_aremove_watches()
  or zoo_aremove_all_watches() cast the caller's data pointer to a sync
  completion and signaled it. This wrote mutex state into application
  memory and could hang in pthread_mutex_lock. aremove_watches() no
  longer signals a sync completion. A local removal is complete when the
  call returns, so the synchronous wrapper waits only for removals that
  go to the server. A local removal does not call the completion, as
  before. The header now documents this.
- zoo_aremove_watches() and zoo_aremove_all_watches() declared the
  completion as void_completion_t *, a pointer to a function pointer.
  Correct callers failed to compile in C++ and with GCC 14. Declare it
  as void_completion_t. The ABI does not change.
- containsWatcher() matched a NULL watcher before it looked up the
  path. A local removal of all watches returned ZOK for a path with no
  watches. Return ZNOWATCHER, as the header documents and as the Java
  client does.

Add the real-server test Zookeeper_simpleSystem::testAsyncRemoveWatchers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oveWatchers

testRemoveWatchers stops the server and does not start it again. It was
the last test in Zookeeper_simpleSystem, so this did not matter before.
testAsyncRemoveWatchers now runs after it and failed with
ZCONNECTIONLOSS in the full suite. Start the server again at the end of
testRemoveWatchers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant