Skip to content

GUACAMOLE-2328: Initialize the FreeRDP GDI within PostConnect, not PreConnect. - #713

Merged
mike-jumper merged 1 commit into
apache:staging/1.6.1from
StuDMr:GUACAMOLE-2328
Sep 10, 2026
Merged

mike-jumper merged 1 commit into
apache:staging/1.6.1from
StuDMr:GUACAMOLE-2328

Conversation

@StuDMr

@StuDMr StuDMr commented Sep 10, 2026

Copy link
Copy Markdown

Fixes GUACAMOLE-2328.

gdi_init() is currently called from the PreConnect callback. It requires that the rdpContext cache already exist, and that cache is not created until the connection sequence reaches Confirm Active, which is after PreConnect has returned. On FreeRDP 3.31.0 and later this dereferences a NULL cache inside gdi_init_ex(), and no RDP session can be established.

Earlier FreeRDP versions created the cache inside gdi_init_ex() itself, so the ordering went unnoticed. FreeRDP were asked about this first and consider PreConnect an unsupported place to call gdi_init(), noting it isn't done in any of their reference clients.

This moves gdi_init() into a new PostConnect callback. The pointer registration and the update handler assignments move with it, because they have to follow gdi_init(): it installs FreeRDP's own BeginPaint, EndPaint and DesktopResize handlers, and would silently replace anything registered earlier. What stays in PreConnect is guac_rdp_push_settings(), the add-in provider registration, and the LoadChannels fallback, all of which need to happen before the connection sequence begins.

graphics is no longer used in rdp_freerdp_pre_connect() and has been removed. The doc comments on both functions have been updated to match.

Testing

Built on Ubuntu 24.04 arm64 and tested against an RDP server that authenticates successfully, counting Guacamole protocol instructions produced after ready so that drawing is exercised rather than just the handshake.

FreeRDP guacamole-server result
3.31.0 1.6.0 as released 4 instructions, guacd worker dies inside freerdp_connect()
3.31.0 this branch 36 instructions, renders
3.30.0 this branch 52 instructions, renders

The 3.30.0 row is included to show the change does not impose a minimum FreeRDP version.

One thing that may help anyone else hitting this: Debian and Ubuntu build FreeRDP with -DNDEBUG, which compiles out the WINPR_ASSERT that would otherwise name the NULL cache. On those builds the failure is a bare SIGSEGV in the guacd child with nothing logged at all, rather than an assertion with a backtrace.

…eConnect.

gdi_init() requires that the rdpContext cache already exist. That cache is not
created until the connection sequence reaches Confirm Active, which occurs after
the PreConnect callback has returned. Calling gdi_init() from PreConnect
therefore dereferences a NULL cache within gdi_init_ex(), aborting or crashing
the connection before any session can be established.

This is only observable with FreeRDP 3.31.0 and later. Earlier versions created
the cache within gdi_init_ex() itself, so the call ordering went unnoticed.
PostConnect is where FreeRDP's own reference clients call gdi_init(), and is
also where the GDI is sized using the display geometry the server actually
negotiated rather than the geometry initially requested.

The pointer registration and update handler assignments move along with
gdi_init(). They must follow it: gdi_init() installs FreeRDP's own BeginPaint,
EndPaint, and DesktopResize handlers, silently replacing anything registered
beforehand.

Verified against both FreeRDP 3.30.0 and 3.31.0, connecting to an RDP server
that authenticates successfully and confirming that drawing instructions
continue to be produced in both cases.
@mike-jumper
mike-jumper merged commit 6fb604f into apache:staging/1.6.1 Sep 10, 2026
1 check 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