mirror of
https://gitlab.freedesktop.org/xorg/xserver.git
synced 2026-06-08 01:08:23 +02:00
The test sends a PresentPixmap request with a notify entry from a
byte-swapped client. Without the fix, the window ID in the notify
is not swapped, causing dixLookupWindow to fail with BadWindow.
With the fix, the window ID is correctly interpreted.
See 925edb6c9e ("present: Fix missing byte swaps in sproc_present_pixmap()")
Assisted-by: Claude:claude-claude-opus-4-6
Part-of: <https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/2212>
178 lines
4.2 KiB
Python
178 lines
4.2 KiB
Python
# SPDX-License-Identifier: MIT
|
|
#
|
|
# Present extension protocol request builders for byteswap testing.
|
|
|
|
import struct
|
|
from dataclasses import dataclass
|
|
|
|
# Present minor opcodes
|
|
PresentQueryVersion = 0
|
|
PresentPixmap = 1
|
|
PresentNotifyMSC = 2
|
|
PresentSelectInput = 3
|
|
PresentQueryCapabilities = 4
|
|
|
|
|
|
@dataclass
|
|
class QueryVersionRequest:
|
|
"""PresentQueryVersion request."""
|
|
|
|
opcode: int
|
|
major: int = 1
|
|
minor: int = 2
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
return struct.pack(
|
|
f"{byte_order}BBHII",
|
|
self.opcode,
|
|
PresentQueryVersion,
|
|
3,
|
|
self.major,
|
|
self.minor,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class SelectInputRequest:
|
|
"""PresentSelectInput request."""
|
|
|
|
opcode: int
|
|
eid: int
|
|
window: int
|
|
event_mask: int = 0
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
return struct.pack(
|
|
f"{byte_order}BBH III",
|
|
self.opcode,
|
|
PresentSelectInput,
|
|
4,
|
|
self.eid,
|
|
self.window,
|
|
self.event_mask,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class QueryCapabilitiesRequest:
|
|
"""PresentQueryCapabilities request."""
|
|
|
|
opcode: int
|
|
target: int
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
return struct.pack(
|
|
f"{byte_order}BBH I",
|
|
self.opcode,
|
|
PresentQueryCapabilities,
|
|
2,
|
|
self.target,
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class PresentNotify:
|
|
"""xPresentNotify structure (8 bytes): window(4) + serial(4)."""
|
|
|
|
window: int
|
|
serial: int = 0
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
return struct.pack(f"{byte_order}II", self.window, self.serial)
|
|
|
|
|
|
@dataclass
|
|
class PixmapRequest:
|
|
"""PresentPixmap request.
|
|
|
|
This is a large request with many fields. All fields are included
|
|
to test that byte-swapping handles them all correctly.
|
|
"""
|
|
|
|
opcode: int
|
|
window: int
|
|
pixmap: int
|
|
serial: int = 0
|
|
valid: int = 0 # region or None
|
|
update: int = 0 # region or None
|
|
x_off: int = 0
|
|
y_off: int = 0
|
|
target_crtc: int = 0
|
|
wait_fence: int = 0
|
|
idle_fence: int = 0
|
|
options: int = 0
|
|
target_msc: int = 0
|
|
divisor: int = 0
|
|
remainder: int = 0
|
|
notifies: list[PresentNotify] | None = None
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
notify_data = b""
|
|
if self.notifies:
|
|
for n in self.notifies:
|
|
notify_data += n.to_bytes(byte_order)
|
|
|
|
base_size = 72 # 18 words
|
|
total_size = base_size + len(notify_data)
|
|
length = total_size // 4
|
|
|
|
header = struct.pack(
|
|
f"{byte_order}BBH" # header: opcode, sub-opcode, length
|
|
f"III" # window, pixmap, serial
|
|
f"II" # valid, update
|
|
f"hh" # x_off, y_off
|
|
f"III" # target_crtc, wait_fence, idle_fence
|
|
f"I" # options
|
|
f"xxxx" # pad
|
|
f"Q" # target_msc (CARD64)
|
|
f"Q" # divisor (CARD64)
|
|
f"Q", # remainder (CARD64)
|
|
self.opcode,
|
|
PresentPixmap,
|
|
length,
|
|
self.window,
|
|
self.pixmap,
|
|
self.serial,
|
|
self.valid,
|
|
self.update,
|
|
self.x_off,
|
|
self.y_off,
|
|
self.target_crtc,
|
|
self.wait_fence,
|
|
self.idle_fence,
|
|
self.options,
|
|
self.target_msc,
|
|
self.divisor,
|
|
self.remainder,
|
|
)
|
|
return header + notify_data
|
|
|
|
|
|
@dataclass
|
|
class NotifyMSCRequest:
|
|
"""PresentNotifyMSC request."""
|
|
|
|
opcode: int
|
|
window: int
|
|
serial: int = 0
|
|
target_msc: int = 0
|
|
divisor: int = 0
|
|
remainder: int = 0
|
|
|
|
def to_bytes(self, byte_order: str = "<") -> bytes:
|
|
return struct.pack(
|
|
f"{byte_order}BBH"
|
|
f"II" # window, serial
|
|
f"xxxx" # pad
|
|
f"Q" # target_msc
|
|
f"Q" # divisor
|
|
f"Q", # remainder
|
|
self.opcode,
|
|
PresentNotifyMSC,
|
|
10, # 40 bytes = 10 words
|
|
self.window,
|
|
self.serial,
|
|
self.target_msc,
|
|
self.divisor,
|
|
self.remainder,
|
|
)
|