Commit Graph
80300 Commits
Author SHA1 Message Date
Vadim Zeitlin da2dcc4636 Modernize the code to use C++11 constexpr and ranged-for
Prefer constexpr to macros and ranged-for to index-based loops.
2026-08-06 21:59:35 +02:00
Vadim Zeitlin c0b25d7e86 Remove code for unsupported wxUSE_UNICODE==0 build
Leave only wxUSE_UNICODE branch and simplify UTF-8 conversions.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 8b70724c6a Replace wxASSERT_MSG with subsequent test with wxCHECK_MSG
This is a more idiomatic way of checking for precondition.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 33321e42f8 Remove unnecessary wxIPCMessageBase dtor definition
Virtual dtor is inherited from the base wxObject class anyhow.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 40ad80f29e Use std::unordered_set instead of set when order doesn't matter
This container is preferred unless we really need the set to be ordered
which is not the case here.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin e636713658 Let compiler generate wxTCPServer ctor
There is no need to define it manually, leaving it as default is shorter
and more clear.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin f17abe5883 Use <define> instead of <cxxflags> in the test bakefile
Prefer using more specialized tag.

Regenerate the affected files.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 25a1baa87c Don't show test information when running it as IPC server
This avoids logging it many times during the full test suite run which
was unnecessary and confusing.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 9c1b1b1ea9 Extract showing information about the test in a separate function
No real changes, just factor out the function for showing information
about the test and its execution environment.
2026-08-06 21:59:34 +02:00
Vadim Zeitlin 975523516c Simplify checks for using the test in "IPC server" mode
Don't duplicate the complex preprocessor check multiple times, just
define wxHAS_TEST_IPC_SERVER once and check for it.

Also define the helper ShouldRunTestIPCServer() function which is more
clear than using wxGetEnv() explicitly.

No real changes.
2026-08-06 21:59:34 +02:00
John Paul Mattia 122ff6d7db Add a multithreaded test for IPC over sockets
Add a test exercising the IPC-over-sockets implementation from a single
thread and from multiple threads concurrently (Execute, Request, Poke,
Advise, combined Advise+Request, and concurrent main-thread and
worker-thread Request()s).

Each test starts its own server by re-executing the test program with
WX_IPC_TEST_SERVER set and shuts it down again in the fixture teardown, so
no server process outlives a test (or disturbs the unrelated GUI tests in
test_gui). The client runs in the main Catch2 process and queries the server
for state to verify it (Catch2 macros cannot run in the server process). The
wait loops are wall-clock bounded so they behave under a GUI event loop, and
a per-fixture watchdog aborts with a diagnostic if a test ever hangs rather
than letting CI time out.

The test runs in both the console "test" and the GUI "test_gui" programs. It
is excluded from one configuration: wxQt, whose event loop does not reliably
process a cross-thread CallAfter() (a wxQt bug fixed separately).
2026-08-06 21:59:34 +02:00
John Paul Mattia 90a9968a1d sckipc: bound the connection attempt by wxIPCTimeout
wxTCPClient::MakeConnection left the client socket at its long default
timeout, so connecting to a listener that is not yet ready to complete the
topic handshake blocked for that default (ten minutes) instead of failing
promptly for the caller to retry. Set the socket timeout to wxIPCTimeout
before connecting, matching the per-connection timeout used afterwards.

Also reword the reply-handoff comment to say the pending reply is serialized
by m_cs_awaiting_reply.
2026-07-09 17:53:51 -07:00
John Paul Mattia 96357aba7f sckipc: prevent re-entrant socket reads under the MSW GUI event loop
The IPC connection sockets are event-notified and wxSOCKET_WAITALL (not
wxSOCKET_BLOCK), so a main-thread Read/Peek that must wait pumps the event
loop. On wxMSW under a GUI event loop that pump re-dispatches a queued
wxSOCKET_INPUT for a socket we are already reading on the main thread, so
OnSocketInput() re-enters and reads the same socket again, tripping
wxSocketReadGuard ("read reentrancy?") and throwing out of the main loop.
This surfaced as the test_gui IPC test failing on wxMSW DLL Release x64;
the console and Linux/Xvfb GUI runs do not re-enter, so they passed. The
recursive m_cs_socket_processing critical section does not catch it.

Add a main-thread re-entrancy guard: track the sockets currently being read
(m_socketsBeingRead) and have OnSocketInput() bail when re-entered for a
socket already being read. The in-progress read consumes the data and the
outer loop / a re-posted wxSOCKET_INPUT drains the rest. SendAndGetReply_
MainThread() marks its socket the same way so a re-dispatched OnSocketInput()
cannot steal the reply. Reads run only on the main thread, so the set needs
no lock.
2026-07-09 17:53:51 -07:00
John Paul Mattia 069a44035e sckipc: fix the two-request deadlock by pumping while waiting on the main thread
A Request() on the main thread concurrent with a worker-thread Request() on the
same connection deadlocked: the worker holds m_cs_awaiting_reply while parked in
RunOnMainThread() waiting for the main thread, and the main thread blocked
acquiring m_cs_awaiting_reply in SendAndGetReply_MainThread(), so it stopped
pumping the event loop the worker needed, and neither could progress.

Fix: the main-thread path no longer blocks on m_cs_awaiting_reply. It spins on
TryEnter(), and between attempts pumps the active event loop
(ProcessPendingEvents() to run the worker's RunOnMainThread() jobs, plus a short
DispatchTimeout() to service its reply). The worker can then finish and release
the lock while the main thread keeps the loop alive. The pump happens before
either lock is taken, so re-entrant OnSocketInput() cannot collide with a lock
we hold; the existing read loop after acquisition is unchanged. A CritSectLeaver
RAII guard releases the manually-entered section on all return paths. If there
is no active event loop (so nothing could advance a worker), it falls back to a
plain blocking Enter().

With this, a main-thread Request() concurrent with a worker-thread Request()
completes instead of hanging. The IPC::ConcurrentMainAndWorkerRequest test added
with the test suite that follows reproduces the original deadlock; with the fix
in place, full [ipc] is green on a plain build and under TSan (no data races,
no hang).
2026-07-09 17:53:51 -07:00
John Paul Mattia 46ea00fd43 sckipc: marshal worker-thread IPC socket I/O to the main thread
wxSocket's event-notification machinery is effectively main-thread-only:
the process-global wxFDIODispatcher's handler map is mutated whenever a
socket re-arms input notification during I/O. Worker threads calling
Request()/Advise()/etc. did that I/O themselves, racing the main event
loop's epoll_wait/dispatch over the dispatcher map, the data race
behind the macOS AdviseAndRequestMultiThread failure (and the Linux
"modify descriptor -1 in epoll" errors).

Route all IPC socket I/O through the main thread: RunOnMainThread() runs
the work directly on the main thread, else marshals it via CallAfter()
and blocks the worker on a semaphore until it completes. The six
worker-callable transaction methods funnel their socket work through it.

Making that path correct under multithreaded use also required:

- ReadMessageFromSocket(): bind the wxIPCMessageNull to the socket before
  ReadIPCCode(), otherwise every connect handshake read an empty message
  and the server refused all connections.
- SendAndGetReply_WorkerThread(): obey the wxCondition contract: hold
  m_replyMutex around the WaitTimeout() (predicate-guarded loop), but NOT
  across WriteMessageToSocket(). Holding it across the marshalled write
  deadlocked the worker against the main thread's
  OnSocketInput()->DeliverPendingReply().
- OnSocketInput(): test the pending-reply match inside DeliverPendingReply()
  under m_replyMutex instead of reading m_pending unlocked (TSan data race).
- Move gs_critical_io acquisition inside the RunOnMainThread() lambda so the
  socket-I/O lock is only ever held on the thread doing the I/O, never across
  the worker->main handoff.

Reply-expecting commands are serialized via m_cs_awaiting_reply, taken in
both the main- and worker-thread paths. A remaining deadlock between a
main-thread and a worker-thread Request() on the same connection is
addressed in the following commit.
2026-07-09 17:53:51 -07:00
John Paul Mattia be2930b325 sckipc: avoid undefined downcast of a freed socket in Client_OnRequest
A shared, process-lifetime handler can receive a socket event queued
before its socket was destroyed. Client_OnRequest obtained the socket via
event.GetSocket(), a checked downcast (wxObject* -> wxSocketBase*) that is
undefined behavior on a freed object and trips UBSAN's vptr check, before
the IsConnectionSocket() registry guard could reject it. Compute the
pointer with reinterpret_cast (not vptr-instrumented) purely for the
registry lookup; the object is only dereferenced once the guard confirms
it is still alive.
2026-07-09 17:53:51 -07:00
John Paul Mattia 7299670bfb sckipc: always re-post wxSOCKET_INPUT after an off-loop message read
FindMessage() may run on a worker thread (Request()/Advise()) off the
main event loop. When it consumes a message, the socket's own
wxSOCKET_INPUT notification for trailing data can already have been taken
and never reach the main loop, so a following message (e.g. an Advise) is
never drained, the lost-wakeup behind the macOS
AdviseAndRequestMultiThread failure. Re-post wxSOCKET_INPUT
unconditionally so the main loop always re-scans the socket; a spurious
event is harmless (the handler peeks, finds nothing, returns).
2026-07-09 17:53:51 -07:00
JP Mattia d22fcfeb85 Fix use-after-free of destroyed IPC socket on the shared event handler
wxTCPEventHandler is a process-wide singleton shared by every IPC
connection and it lives until the program exits. Socket events queued on
it can still be pending after the wxSocketBase they refer to has been
destroyed (e.g. a wxSOCKET_LOST generated while a connection is torn
down). Because wxSocketBase::IsOk() only checks m_impl != nullptr, a
freed socket with a dangling m_impl passes that check and
Client_OnRequest() goes on to call socket->Peek(), dereferencing freed
memory.

This use-after-free crashed reliably under the MSVC debug heap (freed
memory poisoned to 0xFEEEFEEE) and was otherwise silent, manifesting as
an intermittent SIGSEGV in the IPC unit tests on Windows when a stale
event left by one test case was dispatched during the next test's setup.

Track the set of sockets that currently have a live connection in the
handler and ignore socket events for any socket not in that set. The
check only compares pointer values and never dereferences a
possibly-freed socket. Sockets are registered when a connection is
established (client MakeConnection and server Server_OnRequest) and
unregistered when it is torn down (HandleDisconnect and
~wxTCPConnection).
2026-07-09 17:53:51 -07:00
John Paul Mattia 21f88595a8 Fix IPC socket races on Linux
Serialize all wxIPC socket reads and writes under one critical section. Separate read/write locks allowed concurrent access to wxSocketBase from worker and main threads.
2026-07-09 17:53:51 -07:00
JP Mattia d293a00791 Stop throwing away socket read notifications.
FD_CONNECT, FD_WRITE, FD_READ are non-exclusive notifications in
theory, ie there is a notification with an or'd FD_CONNECT|FD_READ. By
throwing this away, there are occasional stoppages in the data flow,
particularly right after connect.

In any case, I don't understand why sockmsw was throwing any
notification away. It should be up to the callback whether or not
action is to be taken on a notification.  As such, I've eliminated
the filter.
2026-07-09 17:53:51 -07:00
JP Mattia 7e54d32fdd Make WSAECONNABORTED and ERROR_ACCESS_DENIED non-fatal.
On windows, reading or peeking when there is no data waiting results
in WSAECONNABORTED and ERROR_ACCESS_DENIED. Since there is no other
way to determine whether or not we've read all information out of the
buffer, make this error non-fatal.
2026-07-09 17:53:51 -07:00
JP Mattia 8bd68bf8e4 Accessor for retrieval of the handler. 2026-07-09 17:53:51 -07:00
JP Mattia c9cd8fb251 We need a pointer to the handler in the connection object. 2026-07-09 17:53:51 -07:00
JP Mattia 0a32834ae0 Moving/rewriting HandleDisconnect. 2026-07-09 17:53:50 -07:00
JP Mattia 36950e8481 Rewrite of IPC_ADVISE_START, IPC_ADVISE_STOP, and IPC_ADVISE 2026-07-09 17:53:50 -07:00
JP Mattia 68a1754e57 Rewrite sending of IPC_POKE message. 2026-07-09 17:53:50 -07:00
JP Mattia 97f442978d Rewrite sending of IPC_REQUEST.
There is a critical section to ensure that there are no overlapping
IPC_REQUESTs. This ensures that there is only one possible
IPC_REQUEST_REPLY for each request.
2026-07-09 17:53:50 -07:00
JP Mattia f3ece5a99f Rewrite sending of IPC_Execute message. 2026-07-09 17:53:50 -07:00
JP Mattia c1bac42f9d Rewrite Disconnect. Eliminate stray streams code. 2026-07-09 17:53:50 -07:00
JP Mattia 2a1c02e520 Rewrite MakeConnection using wxIPCMessage. 2026-07-09 17:53:50 -07:00
JP Mattia 5e0d6ed994 Constant values. Note lack of use for one IPCCode. 2026-07-09 17:53:50 -07:00
JP Mattia c8202e3d76 Create an array to track memory allocation.
One thing in the previous version: Multiple threads requesting
information would run into problems if data reads overlapped, perhaps
in multiple threads.

The source of this problem is that the memory management from data
reads in wxConnection is not transferred to to the caller. So
wxConnection uses a buffer that gets overwritten for every read.

My approach is to create an array of char* pointers: Every memory
allocation is stored in the array, and survives until another
MAX_MSG_BUFFERS is allocated, at which point the previous data is
deleted and a new allocation occurs.

The deletion of previous data is still potentially problematic (the
caller needs to understand that passed data must be copied in a
reasonable amount of time if they plan to keep it around), but at
least the data will have a lifetime greater than one read.

I set the array to 2048 blocks, which was more for my app than
anything, but maybe there's a better value.
2026-07-09 17:53:50 -07:00
JP Mattia cf8770e5a2 Utilities for sending fail message, getting wxTCPConnection. 2026-07-09 17:53:50 -07:00
JP Mattia d44572072b Server_OnRequest rewritten to incorporate wxIPCMessage 2026-07-09 17:53:50 -07:00
JP Mattia 3d944a3f2d FindMessage is used when a reply is expected for a sent message.
As an example, IPC_REQUEST from the client expects the specific reply
of IPC_REQUEST_REPLY. It is possible that the server sneaks in other
messages, such as a stream of IPC_ADVISE data. So FindMessage loops
until the desired message is found, executing any other unexpected
messages that happen to be read first.
2026-07-09 17:53:50 -07:00
JP Mattia b29b29604a ExecuteMessage dispatches based on the IPCCode, and does the work. 2026-07-09 17:53:50 -07:00
JP Mattia 97678bbd33 New version of Client_OnRequest.
- There is no guarentee that a notification from the socket
corresponds to a single wxIPCMessage transmission. So Client_OnRequest
loops in Read/Execute until Peek reveals that there are no further
messages waiting.
2026-07-09 17:53:50 -07:00
JP Mattia 50dd944908 The old Server_OnRequest combined reading and executing. Remove it.
The reading part of the function has been mostly subsumed by
wxIPCMessage.

We will replace the execute shortly.
2026-07-09 17:53:50 -07:00
JP Mattia a8966090b3 The old Client_OnRequest combined reading and executing. Remove it.
The reading part of the function has been mostly subsumed by
wxIPCMessage.

We will replace the execute in a couple of commits.
2026-07-09 17:53:50 -07:00
JP Mattia 53fcc32ed4 Read, write, and peek primitives for comm with the socket.
gs_critical_read and gs_critical_write ensure that only one thread is
reading/writing a message from the socket at any time.
2026-07-09 17:53:50 -07:00
JP Mattia 16646f2385 Fill in the remaining wxIPCMessageBase r/w operations.
Also GetBufPtr() is added to wxTCPEventHandler, which allocates the
memory for reading upon certain events occuring.
2026-07-09 17:53:50 -07:00
JP Mattia 6b0c34493d Utility: Ensure deletion of an IPCMessage when it goes out of scope. 2026-07-09 17:53:50 -07:00
JP Mattia f33dd904bb Create the IPC messages to be passed between processes.
Each IPC Message needs to have

- constructor for reading

- constructor for writing (usually different from read)

- DataToSocket() method for writing

- DataFromSocket() method for reading

The DataToSocket() and DataFromSocket() must be symmetric.
2026-07-09 17:53:50 -07:00
JP Mattia ae8b3738cf wxIPCMessageBase serves as the new socket interface.
- The IPCCode is expanded from 8 bits to 32 bits. The first 24 bits
serve as a constant header to ensure that data sync is not lost.
Before this change, loss of sync meant there was an 11 out of 256
chance that an incoming byte would be interpreted as a command,
possibly leading to a crash. The header reduces the probability by a
factor of 2^24.

- Each derived message (Request, Execute, etc) will have a
DataToSocket() and DataFromSocket() method. These methods allow for
easy verification that the reads and writes are correctly symmetric.

- Pointers to Read and write data are separate member vars, for easier
management of const-params for the wxConnection interface (which we
take to be immutable).

- A pointer back to wxTCPEventHandler is going to be needed for
memory management. More on this in a later commit.
2026-07-09 17:53:50 -07:00
JP Mattia 287cc4282f Remove IPCStreams and IPCOutput, ie the IPC interface to the socket. 2026-07-09 17:53:49 -07:00
Vadim Zeitlin fcdaa107fb Create header for 3.3.4 in the change log
Unix builds / Ubuntu 18.04 wxGTK 3 compatible 3.0 (push) Has been cancelled
Unix builds / Ubuntu 24.04 wxGTK ASAN not compatible (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK UTF-8 (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxQt (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxX11 (push) Has been cancelled
Unix builds / Ubuntu 20.04 wxGTK 3 with clang (push) Has been cancelled
Unix builds / Ubuntu 22.04 wxGTK with wx containers (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxDFB (push) Has been cancelled
Unix builds / Ubuntu 24.04 wxGTK UBSAN (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK 3 static with gcc 4.8 (push) Has been cancelled
Unix builds / Ubuntu 18.04 wxGTK 2 (push) Has been cancelled
CMake builds / Ubuntu 22.04 wxGTK 3 (push) Has been cancelled
CMake builds / macOS latest wxGTK 3 Unix Makefiles (push) Has been cancelled
CMake builds / MSW/MSVC wxMSW (push) Has been cancelled
CMake builds / MSW/Clang wxMSW (push) Has been cancelled
CMake builds / macOS latest wxOSX Ninja (push) Has been cancelled
CMake builds / macOS 14 wxOSX Xcode (push) Has been cancelled
CMake builds / macOS 14 wxIOS (push) Has been cancelled
CMake builds / MSW/MSVC wxQt 5.15 (push) Has been cancelled
CMake builds / MSW/MSVC wxQt 6.10 (push) Has been cancelled
Mac builds / wxMac ARM ASAN not compatible (push) Has been cancelled
Mac builds / wxMac Universal C++14 (push) Has been cancelled
Mac builds / wxiOS Simulator on Silicon Mac (push) Has been cancelled
Mac builds / wxiOS (push) Has been cancelled
Mac builds / wxMac Intel C++17 (push) Has been cancelled
Mac Xcode builds / iOS Simulator static (push) Has been cancelled
Mac Xcode builds / macOS dynamic Release (push) Has been cancelled
Mac Xcode builds / iOS static Debug (push) Has been cancelled
MSW builds / wxMSW vs2022 DLL Debug x64 (push) Has been cancelled
MSW builds / wxMSW vs2022 DLL Release x64 (push) Has been cancelled
MSW builds / wxMSW vs2022 Debug Win32 (push) Has been cancelled
MSW builds / wxMSW vs2022 Release arm64 (push) Has been cancelled
MSW builds / wxMSW vs2026 DLL Release x64 (push) Has been cancelled
MSW cross-builds / wxMSW 64 bits not compatible (push) Has been cancelled
MSW cross-builds / wxMSW/Univ (push) Has been cancelled
MSW cross-builds / wxMSW 32 bits (push) Has been cancelled
Code Checks / Check Spelling (push) Has been cancelled
Code Checks / Check Whitespace (push) Has been cancelled
Code Checks / Check Mixed EOL (push) Has been cancelled
Code Checks / Check C++ Style (push) Has been cancelled
Code Checks / Check All Headers In allheaders.h (push) Has been cancelled
Update Documentation / Update Online Documentation (push) Has been cancelled
Restore instructions for updating it removed as part of preparation for
3.3.3.
2026-07-09 15:09:57 +02:00
Vadim Zeitlin 5ccdcd6b2a Update version to 3.3.4
Run misc/scripts/inc_release, update version.bkl and rebake.
2026-07-09 15:08:08 +02:00
Vadim Zeitlin 55423d3745 Record checksums for 3.3.3 release files
Note that source archives checksums have surreptitiously changed since
the initial announcement as the archives had to be rebuilt. The ones
here are the correct ones.
2026-07-09 15:06:03 +02:00
Vadim Zeitlin 35264a22cc Add reminder to check that website update workflow ran
It gets disabled due to inactivity and needs to be manually enabled to
run again.
2026-07-07 21:10:39 +02:00
Stefan Csomor 565553ee98 Make default background color transparent in wxOSX
This is needed for translucency effects, desktop background images
changing the toplevel window background tint.

Also don't erase background when no background color is specified.

Closes #26301.
v3.3.3.1
2026-07-07 20:39:53 +02:00