Skip to content

fix(pdu): keep the packed byte of RLEX segments when the palette has a single entry - #1903

Merged
Benoît Cortier (CBenoit) merged 4 commits into
Devolutions:masterfrom
AdrienAvalon:fix/rlex-single-palette-packed-byte
Oct 8, 2026
Merged

Benoît Cortier (CBenoit) merged 4 commits into
Devolutions:masterfrom
AdrienAvalon:fix/rlex-single-palette-packed-byte

Conversation

@AdrienAvalon

Copy link
Copy Markdown
Contributor

Closes #1902.

decode_rlex special-cased a one-entry palette (stop_index_bits = 0, bare run lengths). Per MS-RDPEGFX 2.2.4.6.2.2 and FreeRDP's clear_decompress_subcode_rlex (CLEAR_LOG2_FLOOR[0] == 0), stopIndex still takes one bit in that case and every segment keeps its packed byte. The shortcut read every run length one byte off and rejected the one-colour regions Windows Server uses for the solid corners of its taskbar (14×64, 64×46) with "suite exceeds region pixel count".

This PR gives stopIndex one bit for a single entry, removes the special path, and adds a test decoding such a 14×64 region (a run of 895 on a 16-bit length plus a suite of one). No encoder emitted the old form. cargo test -p ironrdp-pdu rlex: 8 passed.

Shipped in avash's vendored ironrdp-pdu since 0.7.1, verified against Windows Server 2025 with the recorded session that exposed it.

@github-actions github-actions Bot added kind/protocol Affects RDP or related protocol behavior needs-review A human reviewer is the current next actor risk/medium Behavioral change that does not substantially alter a core public API scope/core Touches the core architectural tier size/S Size: up to 199 counted lines and 5 files; exceeds XS in either measure labels Sep 4, 2026
@CBenoit
Benoît Cortier (CBenoit) requested a balanced review from Copilot September 4, 2026 20:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The full test suite fails because an existing one-entry RLEX fixture was not updated.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Fixes single-entry RLEX palette decoding by preserving the mandatory packed segment byte.

Changes:

  • Uses one stopIndex bit for single-entry palettes.
  • Removes the obsolete bare-run decoder path.
  • Adds a Windows Server regression test.
File summaries
File Review
crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs Corrects RLEX parsing. The existing subcodec fixture must include the packed byte and updated bitmap length. Renaming the helper to decode_segments is a non-blocking nit.
Review details

Suppressed comments (1)

crates/ironrdp-pdu/src/codecs/clearcodec/rlex.rs:87

  • Now that this path also handles one-entry palettes, decode_multi_palette_segments no longer describes the helper's responsibility. Rename it to decode_segments so future changes do not mistakenly assume the helper is only valid for multi-entry palettes.
    decode_multi_palette_segments(
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Balanced

&mut segments,
)?;
}
decode_multi_palette_segments(

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking. On this branch cargo test -p ironrdp-pdu passes (423 tests, and the CI checks are green): decode_subcodec_layer only records each region with its codec id and never runs the RLEX decoder on it, so this fixture was not parsed. It did still describe the old encoding, so 399ea8c makes it a valid one-entry RLEX stream (bitmap length 6, a zero packed byte before the run length), as you suggested.

Comment thread crates/ironrdp-pdu/src/codecs/clearcodec/subcodec.rs Outdated

@CBenoit Benoît Cortier (CBenoit) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@github-actions

Copy link
Copy Markdown
Contributor

Automated review will not run because this contributor is not yet eligible under the automation policy.

Contributors become eligible after one qualifying IronRDP pull request is merged into master. Maintainer review is required.

@CBenoit

Copy link
Copy Markdown
Member

Adrien CROS (@AdrienAvalon) I think this just needs the formatter to run, can you look into that, please?

@CBenoit Benoît Cortier (CBenoit) added needs-author-action The pull request author is the current next actor and removed needs-review A human reviewer is the current next actor labels Oct 1, 2026
auto-merge was automatically disabled October 6, 2026 17:17

Head branch was pushed to by a user without write access

@AdrienAvalon
Adrien CROS (AdrienAvalon) force-pushed the fix/rlex-single-palette-packed-byte branch from 9421798 to 07ed330 Compare October 6, 2026 17:18
@AdrienAvalon

Copy link
Copy Markdown
Contributor Author

Thanks Benoît Cortier (@CBenoit), done: rebased on master and ran the formatter (07ed330), whose newer config orders the ironrdp_core imports in subcodec.rs differently. cargo xtask check fmt passes, and cargo test -p ironrdp-pdu (426 tests) and clippy on the crate are green locally.

@github-actions github-actions Bot added automation-failed Exact-head automated classification or review failed or was unavailable risk/unknown Risk could not be determined automatically; needs maintainer-level scrutiny and removed needs-author-action The pull request author is the current next actor risk/medium Behavioral change that does not substantially alter a core public API labels Oct 6, 2026
@AdrienAvalon

Copy link
Copy Markdown
Contributor Author

Note on the one red check, Check public API compatibility: it fails before comparing any API, while building rustdoc for ironrdp with freshly resolved dependencies. sspi 0.21.3 does not compile against picky-krb 0.12.5 (GssApiMessageError::InvalidMechanismOid not covered, E0004), which looks like what #2080 addresses. This PR only touches ironrdp-pdu's RLEX decoder and its tests.

@CBenoit

Copy link
Copy Markdown
Member

PR automation is failing because of a picky-krb 0.12.5 incompatibility, fixed on master by #2074. Please rebase on master to fix it.

…a single entry

MS-RDPEGFX 2.2.4.6.2.2 gives stopIndex floor(log2(paletteCount - 1)) + 1
bits; with a single palette entry FreeRDP's CLEAR_LOG2_FLOOR table yields
0, so stopIndex still takes one bit and every segment keeps its packed
byte. The single-entry shortcut read bare run lengths instead, one byte
off, and failed with "suite exceeds region pixel count" on the solid
taskbar corners Windows Server encodes this way (14x64, 64x46).

Closes Devolutions#1902
The subcodec layer only records the region and its codec id, so this
fixture is never parsed by the RLEX decoder and the test kept passing.
It still documented the old, incorrect encoding (no packed byte when the
palette has a single entry); make it match what the decoder now expects
so the fixture stays a valid RLEX stream.
Rebased on master, whose rustfmt configuration orders the ironrdp_core
imports differently; cargo xtask check fmt now passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPFSPcmEWGpgTDP24ADEkZ
@AdrienAvalon
Adrien CROS (AdrienAvalon) force-pushed the fix/rlex-single-palette-packed-byte branch from 07ed330 to b523188 Compare October 7, 2026 13:25
@AdrienAvalon

Copy link
Copy Markdown
Contributor Author

Rebased on master with #2074 (b523188). cargo xtask check fmt passes, cargo test -p ironrdp-pdu (426 tests) and clippy on the crate are green locally. Thanks for the pointer!

@AdrienAvalon

Copy link
Copy Markdown
Contributor Author

After the rebase, Check public API compatibility now fails differently (run): cargo-semver-checks stops on unsupported rustdoc format v61 while reading target/doc/ironrdp.json, before comparing anything with the baseline 4132836. It looks like the semver-checks binary in the automation predates the rustdoc JSON format of the toolchain it runs with; the branch itself only changes ironrdp-pdu's RLEX decoder and tests, and its rust-toolchain.toml is master's.

@github-actions github-actions Bot added risk/medium Behavioral change that does not substantially alter a core public API and removed risk/unknown Risk could not be determined automatically; needs maintainer-level scrutiny automation-failed Exact-head automated classification or review failed or was unavailable labels Oct 7, 2026
@CBenoit
Benoît Cortier (CBenoit) enabled auto-merge (squash) October 8, 2026 04:29
@CBenoit
Benoît Cortier (CBenoit) merged commit 8e76c31 into Devolutions:master Oct 8, 2026
42 of 43 checks passed

This branch was successfully deployed

1 active deployment
llm-providers — b523188a Deployed Oct 7, 2026 by AdrienAvalon via Classify pull request #1703
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/protocol Affects RDP or related protocol behavior risk/medium Behavioral change that does not substantially alter a core public API scope/core Touches the core architectural tier size/S Size: up to 199 counted lines and 5 files; exceeds XS in either measure

Development

Successfully merging this pull request may close these issues.

clearcodec: RLEX regions with a single palette entry are parsed without their packed byte

3 participants