xkb: pass x_rpcbuf_t into XkbAssembleMap()

The keymap assembly machinery is a horribly complicated machinery,
because often whole replies with variable sized payloads can be nested
into each other. It's time to use x_rpcbuf_t for that, but's is not an
easy thing to do and really a huge change - therefore doing this in small
and easy to digest step.

At first, let XkbAssembleMap() operate on a x_rpcbuf_t. But for now just
let it use the x_rpcbuf_t's raw buffer directly (because it's callees cant
work on this yet) - thus XkbAssembleMap() yet need to make enough room
in the buffer before calling in.

For the time being we're allocating far too much (because calculating
the actually need amount would be too complicated here) and having an
extra memcpy(). But it's just an intermediate step anyways - subsequent
commits will convert everything down the whole call chain into using
x_rpcbuf_t operations, so that extra overhead can be dropped again later.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
This commit is contained in:
Enrico Weigelt, metux IT consult 2025-07-15 22:19:19 +02:00 committed by Enrico Weigelt
commit 742443ea73

View file

@ -33,6 +33,7 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <X11/extensions/XKMformat.h>
#include "dix/dix_priv.h"
#include "dix/rpcbuf_priv.h"
#include "miext/extinit_priv.h"
#include "os/osdep.h"
#include "xkb/xkbfmisc_priv.h"
@ -1014,19 +1015,12 @@ XkbSizeKeyTypes(XkbDescPtr xkb, xkbGetMapReply * rep)
return len;
}
static char *
XkbWriteKeyTypes(XkbDescPtr xkb, CARD8 firstType, CARD8 nTypes,
char *buf, ClientPtr client)
static void XkbWriteKeyTypes(XkbDescPtr xkb, CARD8 firstType, CARD8 nTypes,
x_rpcbuf_t *rpcbuf, ClientPtr client)
{
XkbKeyTypePtr type;
unsigned i;
xkbKeyTypeWireDesc *wire;
type = &xkb->map->types[firstType];
for (i = 0; i < nTypes; i++, type++) {
register unsigned n;
wire = (xkbKeyTypeWireDesc *) buf;
XkbKeyTypePtr type = &xkb->map->types[firstType];
for (int i = 0; i < nTypes; i++, type++) {
xkbKeyTypeWireDesc *wire = x_rpcbuf_reserve(rpcbuf, sizeof(xkbKeyTypeWireDesc));
wire->mask = type->mods.mask;
wire->realMods = type->mods.real_mods;
wire->virtualMods = type->mods.vmods;
@ -1037,13 +1031,14 @@ XkbWriteKeyTypes(XkbDescPtr xkb, CARD8 firstType, CARD8 nTypes,
swaps(&wire->virtualMods);
}
buf = (char *) &wire[1];
if (wire->nMapEntries > 0) {
xkbKTMapEntryWireDesc *ewire;
XkbKTMapEntryPtr entry;
if (type->map_count > 0) {
void *space = x_rpcbuf_reserve(
rpcbuf, sizeof(xkbKTMapEntryWireDesc) * type->map_count);
xkbKTMapEntryWireDesc *ewire = space;
XkbKTMapEntryPtr entry = type->map;
size_t n;
ewire = (xkbKTMapEntryWireDesc *) buf;
entry = type->map;
for (n = 0; n < type->map_count; n++, ewire++, entry++) {
ewire->active = entry->active;
ewire->mask = entry->mods.mask;
@ -1054,13 +1049,12 @@ XkbWriteKeyTypes(XkbDescPtr xkb, CARD8 firstType, CARD8 nTypes,
swaps(&ewire->virtualMods);
}
}
buf = (char *) ewire;
if (type->preserve != NULL) {
xkbModsWireDesc *pwire;
XkbModsPtr preserve;
pwire = (xkbModsWireDesc *) buf;
preserve = type->preserve;
if (type->preserve != NULL) {
xkbModsWireDesc *pwire = x_rpcbuf_reserve(
rpcbuf, sizeof(xkbModsWireDesc) * type->map_count);
XkbModsPtr preserve = type->preserve;
for (n = 0; n < type->map_count; n++, pwire++, preserve++) {
pwire->mask = preserve->mask;
pwire->realMods = preserve->real_mods;
@ -1069,11 +1063,9 @@ XkbWriteKeyTypes(XkbDescPtr xkb, CARD8 firstType, CARD8 nTypes,
swaps(&pwire->virtualMods);
}
}
buf = (char *) pwire;
}
}
}
return buf;
}
static int
@ -1403,11 +1395,13 @@ XkbComputeGetMapReplySize(XkbDescPtr xkb, xkbGetMapReply * rep)
return Success;
}
static void
XkbAssembleMap(ClientPtr client, XkbDescPtr xkb, xkbGetMapReply rep, char *desc)
static void XkbAssembleMap(ClientPtr client, XkbDescPtr xkb,
xkbGetMapReply rep, x_rpcbuf_t *rpcbuf)
{
if (rep.nTypes > 0)
desc = XkbWriteKeyTypes(xkb, rep.firstType, rep.nTypes, desc, client);
XkbWriteKeyTypes(xkb, rep.firstType, rep.nTypes, rpcbuf, client);
char *desc = rpcbuf->buffer + rpcbuf->wpos;
if (rep.nKeySyms > 0)
desc = XkbWriteKeySyms(xkb, rep.firstKeySym, rep.nKeySyms, desc, client);
if (rep.nKeyActs > 0)
@ -1546,11 +1540,12 @@ ProcXkbGetMap(ClientPtr client)
return status;
int payload_len = (rep.length * sizeof(CARD32)) - (sizeof(xkbGetMapReply) - sizeof(xGenericReply));
char *payload_buf = calloc(1, payload_len);
if (!payload_buf)
x_rpcbuf_t rpcbuf = { .swapped = client->swapped, .err_clear = TRUE };
if (!x_rpcbuf_makeroom(&rpcbuf, payload_len))
return BadAlloc;
XkbAssembleMap(client, xkb, rep, payload_buf);
XkbAssembleMap(client, xkb, rep, &rpcbuf);
if (client->swapped) {
swaps(&rep.sequenceNumber);
@ -1560,9 +1555,11 @@ ProcXkbGetMap(ClientPtr client)
swaps(&rep.totalActs);
}
if (rpcbuf.error)
return BadAlloc;
WriteToClient(client, sizeof(xkbGetMapReply), &rep);
WriteToClient(client, payload_len, payload_buf);
free(payload_buf);
WriteToClient(client, payload_len, rpcbuf.buffer);
return Success;
}
@ -6053,8 +6050,19 @@ ProcXkbGetKbdByName(ClientPtr client)
}
if (reported & (XkbGBN_SymbolsMask | XkbGBN_TypesMask)) {
char *buf = payload_walk + sizeof(mrep);
XkbAssembleMap(client, new, mrep, buf);
x_rpcbuf_t rpcbuf = { .swapped = client->swapped, .err_clear = TRUE };
/* allocating far too much, but it's just temporary */
if (!x_rpcbuf_makeroom(&rpcbuf, payload_length * 4)) {
free(payload_buffer);
return BadAlloc;
}
XkbAssembleMap(client, new, mrep, &rpcbuf);
if (rpcbuf.error) {
free(payload_buffer);
return BadAlloc;
}
if (client->swapped) {
swaps(&mrep.sequenceNumber);
@ -6064,8 +6072,14 @@ ProcXkbGetKbdByName(ClientPtr client)
swaps(&mrep.totalActs);
}
// struct is 8 bytes (2 units) longer than generic reply, so need to
// compute the payload length carefully
const size_t payloadBytes = (mrep.length * 4) - (sizeof(mrep) - sizeof(xGenericReply));
memcpy(payload_walk, &mrep, sizeof(mrep));
payload_walk = buf + (mrep.length * 4) - (sizeof(mrep) - sizeof(xGenericReply));
payload_walk += sizeof(mrep);
memcpy(payload_walk, rpcbuf.buffer, payloadBytes);
payload_walk += payloadBytes;
x_rpcbuf_clear(&rpcbuf);
}
if (reported & XkbGBN_CompatMapMask) {