Skip to content

Conversation

mahiro21h
Copy link

currently, the xserver can crash when running with xnamespace extension enabled when closing clients. this is due to the client's namespace being cleared when the client closes but before other code is done using its value. this pr solves this by adding a new client state before ClientStateGone and having all other code use this new state. this way xnamespace can clear the client's namespace after the other code is done using its value.

this pr also changes code in xnamespace to print everything into the xserver's log by having all XNS log macros call LogMessage() instead and replacing all instances of printf with XNS_LOG().

closes: #486

unsigned int clientGone:1;
unsigned int closeDownMode:2;
unsigned int clientState:2;
unsigned int clientState:3;
Copy link
Contributor

Choose a reason for hiding this comment

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

oh, damn, I'm not sure whether we can do that, because it might change ABI.

maybe we can get away with this in that particular case, because we don't have more of those bits-limited fields after it - smart_priority is a usual char, so I'd guess it's going into next storage unit. but I'm not entirely sure right now.

@HaplessIdiot @algrid @dec05eba @X11Libre/reviewers @X11Libre/wranglers how do you think about this ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Posix says CHAR_BIT == 8.
Before this change, the struct layout was:

char
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :2;
unsigned int :2;
signed char

Now, it's:

char
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :1;
unsigned int :2;
unsigned int :3; /* 1 bit more than before */
unsigned int :7; /* extra padding */
signed char

This breaks abi.

Do X clients need to care about this abi, or is this just for modules?

Copy link
Contributor

@cepelinas9000 cepelinas9000 Sep 17, 2025

Choose a reason for hiding this comment

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

Damn that painful and to make problem worse these fields count up to 8 bits (char) :/ And testing on linux 64 bit platform is very bad: smart_priority moves to next alignment unit... :

#clientState:2
cc base=0x7fffffffd490 majorop=0x7fffffffd4c6 minorop=0x7fffffffd4c7 smart_priority=0x7fffffffd4c9
#clientState3:
cc base=0x7fffffffd490 majorop=0x7fffffffd4c6 minorop=0x7fffffffd4c7 smart_priority=0x7fffffffd4ca

it generated from code:

diff --git a/dix/main.c b/dix/main.c
index 5a9e515cc..3da4a31f8 100644
--- a/dix/main.c
+++ b/dix/main.c
@@ -130,6 +130,12 @@ CallbackListPtr PostInitRootWindowCallback = NULL;
 int
 dix_main(int argc, char *argv[], char *envp[])
 {
+
+    struct _Client c1;
+
+    printf("cc base=%p majorop=%p minorop=%p smart_priority=%p\n",&c1,&c1.majorOp,&c1.minorOp,&c1.smart_priority);
+    fflush(stdout);
+
     int i;
     HWEventQueueType alwaysCheckForInput[2];

Only one my suggestion is to add field at end of struct and when ClientStateGone is set, then check by last field state, for example ClientStateGone_Gone or ClientStateGone_Closing (it will complicate code but leave ABI intact)

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe the dixprivate api can be used to avoid breaking abi?

Copy link
Author

Choose a reason for hiding this comment

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

because it might change ABI

i can't believe i didn't think of that, you're right. it's probably safer to find another alternative.

Copy link
Author

Choose a reason for hiding this comment

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

just saw you guys' replies. metux's solution of adding a new filed to NewClientInfoRec appears to work fine for now. it doesn't require that many changes too, so i'm going to go with it. the new client state can be added at a later time.

Copy link
Contributor

Choose a reason for hiding this comment

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

This breaks abi.

Do X clients need to care about this abi, or is this just for modules?

Not the clients, but drivers. Especially Nvidia. I have no idea whether they're accessing any field down below, but that sounds like an actual risk.

@metux
Copy link
Contributor

metux commented Sep 17, 2025

hmm, maybe it's better adding action field to NewClientInfoRec telling what really happens, so we look at this instead of the current state. And then add another call right at the place where the client is destroyed

@mahiro21h
Copy link
Author

sounds good to me for now. i'll try and see what happens.

@mahiro21h
Copy link
Author

@metux is it all good now?

for (int i=0; i<at->authTokenLen; i++)
printf("%02X", (unsigned char)at->authTokenData[i]);
printf("\"\n");
XNS_LOG("%02X", (unsigned char)at->authTokenData[i]);
Copy link
Contributor

Choose a reason for hiding this comment

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

this would move each single output byte into a new line ... is that really intended ?

Copy link
Author

Choose a reason for hiding this comment

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

no, it's not. i noticed the bytes being outputted incorrectly and was going to undo this change while rebasing but i forgot. i'll undo it later.

ClientPtr client;
xConnSetupPrefix *prefix;
xConnSetup *setup;
Bool action; /* added temporarily for use by xnamespace only */
Copy link
Contributor

Choose a reason for hiding this comment

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

why not an enum with all possible things that could have happened ?
callees then wouldn't look at the client's state bits anymore, but instead this enum.

Copy link
Author

Choose a reason for hiding this comment

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

i did this because it's supposed to be a temporary fix until we can add a new client state. it's not supposed to replace the client state. did i misunderstand what you wanted when you suggested adding action field?

Copy link
Contributor

Choose a reason for hiding this comment

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

my idea was adding an field in here telling the actual reason for the hook to be called.

Copy link
Author

Choose a reason for hiding this comment

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

ok i'll fix it

xnamespace is currently the only code that needs
to do its work at a later time because other code
relies on it when sending window unmap events for
example.

so we will add a special field `state` in
NewClientInfoRec for it.

Signed-off-by: Raysan Al-Awami <raysanalawami@gmail.com>
check param->state instead of checking the
client's state. also, only clear namespace when
param->state is NewClientInfoStateFreedResources.

Signed-off-by: Raysan Al-Awami <raysanalawami@gmail.com>
Signed-off-by: Raysan Al-Awami <raysanalawami@gmail.com>
Signed-off-by: Raysan Al-Awami <raysanalawami@gmail.com>
ClientPtr client;
xConnSetupPrefix *prefix;
xConnSetup *setup;
unsigned int state:3; /* added temporarily for use by xnamespace only */
Copy link
Contributor

Choose a reason for hiding this comment

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

why not the enum ?

Copy link
Author

Choose a reason for hiding this comment

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

i wanted to do it, but i decided to remain consistent with the rest of the server's code. afaik the server's code defines fields that are supposed to be set using enums as bit-fields.

NewClientInfoStateRetained,
NewClientInfoStateGone,
NewClientInfoStateFreedResources
} NewClientInfoState;
Copy link
Contributor

Choose a reason for hiding this comment

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

let's better call it something with "action" or "event", etc.
the idea: this shall tell what's happening right now - IOW: what's the reason for this hook to be called at all.

OR: add an entirely new hook that's called just right before a clientrec is actually destroyed. maybe that's the even better way to do this.

@metux
Copy link
Contributor

metux commented Sep 18, 2025

after sleeping over this, I'm thinking we should do it a much simpler way: just add new new callback that's fired when a client is actually destroyed, and leave the existing hook alone.

metux added a commit that referenced this pull request Sep 18, 2025
Existing client-state hook isn't sufficient for this, and so easy to
be extended cleanly (*1). Adding a new callback is trivial and cheap,
so preferring this way, instead of trying to tweak the existing hook
for something it's never been designed for.

*1) see discussion here: #1077

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
metux added a commit that referenced this pull request Sep 18, 2025
Existing client-state hook isn't sufficient for this, and so easy to
be extended cleanly (*1). Adding a new callback is trivial and cheap,
so preferring this way, instead of trying to tweak the existing hook
for something it's never been designed for.

*1) see discussion here: #1077

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
@metux
Copy link
Contributor

metux commented Sep 18, 2025

Here's a very simple and straightforward approach: just adding a new callback.

#1090

Once that's merged, we easily use it for fixing this bug - no need to ever tinker with client-state's

@metux
Copy link
Contributor

metux commented Sep 18, 2025

Here's a very simple and straightforward approach: just adding a new callback.

#1090

Once that's merged, we easily use it for fixing this bug - no need to ever tinker with client-state's

Hacked up a quick fix based on this in branch wip/client-destroy-hook - haven't had the time to really test it yet.

metux added a commit that referenced this pull request Sep 22, 2025
Existing client-state hook isn't sufficient for this, and so easy to
be extended cleanly (*1). Adding a new callback is trivial and cheap,
so preferring this way, instead of trying to tweak the existing hook
for something it's never been designed for.

*1) see discussion here: #1077

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
@metux
Copy link
Contributor

metux commented Sep 22, 2025

Here's a very simple and straightforward approach: just adding a new callback.

#1090

Once that's merged, we easily use it for fixing this bug - no need to ever tinker with client-state's

It's merged now, so we can use it.

metux added a commit that referenced this pull request Sep 26, 2025
Existing client-state hook isn't sufficient for this, and so easy to
be extended cleanly (*1). Adding a new callback is trivial and cheap,
so preferring this way, instead of trying to tweak the existing hook
for something it's never been designed for.

*1) see discussion here: #1077

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
metux added a commit that referenced this pull request Sep 26, 2025
Existing client-state hook isn't sufficient for this, and so easy to
be extended cleanly (*1). Adding a new callback is trivial and cheap,
so preferring this way, instead of trying to tweak the existing hook
for something it's never been designed for.

*1) see discussion here: #1077

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
@metux
Copy link
Contributor

metux commented Sep 26, 2025

@mahiro21h needs rebase and resolving conflicts.
perhaps the issue already is resolved by recent commits (new callback)

@github-actions
Copy link

Merge Conflict found

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.

4 participants