🎯 portal-probe: omitir persist_mode MATA al portal — por eso Start no contestaba nunca
Causa raíz de que ScreenCast se quedara colgado en Start, medida en metal (OptiPlex 3060).
No era el EGL por software de QEMU: en metal, con iris por hardware, pasaba exactamente
lo mismo. Esa hipótesis queda falsificada.
Lo que pasa de verdad, con cuatro segfaults reproducibles (uno por intento, todos `at 0`
y todos en el MISMO offset de libc, 0x34f64 = `strlen`):
1. el cliente no manda `persist_mode` ⇒ el portal asume PERSIST_MODE_NONE
2. el backend de COSMIC devuelve `restore_data` de todos modos
3. xdg-desktop-portal 1.18.4 entra por la rama NONE de
xdp_session_persistence_generate_and_save_restore_token, que hace
`g_clear_pointer(in_out_restore_token, g_free)` — token = NULL
4. a la vuelta, el llamador hace `g_variant_new_string(*in_out_restore_token)` SIN
comprobar nada ⇒ glib llama strlen(NULL) ⇒ SIGSEGV
El portal muere JUSTO ANTES de emitir el Response. Desde el cliente eso se ve como «Start
aceptado y nunca contesta», que es indistinguible de un backend que se cuelga — y nos
mandó a buscar el problema en la GPU durante meses.
Con persist_mode >= 1 el token se genera (uuid) y no hay nulo. Es un fallo de aguas
arriba; esto lo esquiva desde el cliente sin tocar el portal. Por defecto 1 (transitorio),
que es lo que quiere cualquiera que sólo va a capturar una vez.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@
|
|||||||
* el path para recién ahí hacer `AddMatch`, el portal puede haber emitido ya la señal y se pierde
|
* el path para recién ahí hacer `AddMatch`, el portal puede haber emitido ya la señal y se pierde
|
||||||
* para siempre. Es una carrera real, no teórica.
|
* para siempre. Es una carrera real, no teórica.
|
||||||
*
|
*
|
||||||
* Uso: portal-probe screencast [--multiple] [--window] [--wait N]
|
* Uso: portal-probe screencast [--multiple] [--window] [--wait N] [--persist 0|1|2]
|
||||||
* portal-probe filechooser [--save]
|
* portal-probe filechooser [--save]
|
||||||
* portal-probe screenshot [--wait N]
|
* portal-probe screenshot [--wait N]
|
||||||
* portal-probe version (qué interfaces sirve el portal, y en qué versión)
|
* portal-probe version (qué interfaces sirve el portal, y en qué versión)
|
||||||
@@ -246,7 +246,7 @@ static int g_wait_s = 60;
|
|||||||
|
|
||||||
/* ── ScreenCast: el handshake de CUATRO pasos ─────────────────────────────────────────────────── */
|
/* ── ScreenCast: el handshake de CUATRO pasos ─────────────────────────────────────────────────── */
|
||||||
|
|
||||||
static int do_screencast(DBusConnection *bus, int multiple, int window)
|
static int do_screencast(DBusConnection *bus, int multiple, int window, int persist)
|
||||||
{
|
{
|
||||||
const char *IF = "org.freedesktop.portal.ScreenCast";
|
const char *IF = "org.freedesktop.portal.ScreenCast";
|
||||||
char tok[64], path[512], session[256] = {0};
|
char tok[64], path[512], session[256] = {0};
|
||||||
@@ -286,6 +286,17 @@ static int do_screencast(DBusConnection *bus, int multiple, int window)
|
|||||||
opt_u32(&arr, "types", window ? 2 : 1);
|
opt_u32(&arr, "types", window ? 2 : 1);
|
||||||
opt_bool(&arr, "multiple", multiple ? TRUE : FALSE);
|
opt_bool(&arr, "multiple", multiple ? TRUE : FALSE);
|
||||||
opt_u32(&arr, "cursor_mode", 2); /* 1=oculto 2=embebido 4=metadatos */
|
opt_u32(&arr, "cursor_mode", 2); /* 1=oculto 2=embebido 4=metadatos */
|
||||||
|
/* persist_mode NO es un lujo: OMITIRLO CUELGA EL PORTAL. Medido en metal el 2026-08-06.
|
||||||
|
* Sin esta opción el portal asume PERSIST_MODE_NONE; el backend de COSMIC devuelve
|
||||||
|
* `restore_data` igual, y xdg-desktop-portal 1.18.4 entra por la rama NONE de
|
||||||
|
* xdp_session_persistence_generate_and_save_restore_token, que hace
|
||||||
|
* `g_clear_pointer(in_out_restore_token, g_free)` — deja el token en NULL — y a la vuelta
|
||||||
|
* el llamador hace `g_variant_new_string(*in_out_restore_token)` SIN comprobarlo.
|
||||||
|
* glib llama strlen(NULL) y el portal muere con SIGSEGV justo antes de emitir el Response.
|
||||||
|
* Desde el cliente se ve como «Start aceptado y nunca contesta»: el proceso que debía
|
||||||
|
* responder ya no existe. Con persist_mode >= 1 el token se genera (uuid) y no hay nulo.
|
||||||
|
* Es un fallo de aguas arriba; esto lo esquiva sin tocar el portal. */
|
||||||
|
opt_u32(&arr, "persist_mode", (dbus_uint32_t)persist);
|
||||||
dbus_message_iter_close_container(&it, &arr);
|
dbus_message_iter_close_container(&it, &arr);
|
||||||
if (!call_request(bus, m, "SelectSources")) return 1;
|
if (!call_request(bus, m, "SelectSources")) return 1;
|
||||||
}
|
}
|
||||||
@@ -413,12 +424,13 @@ int main(int argc, char **argv)
|
|||||||
setvbuf(stdout, NULL, _IOLBF, 0);
|
setvbuf(stdout, NULL, _IOLBF, 0);
|
||||||
|
|
||||||
const char *cmd = argc > 1 ? argv[1] : "version";
|
const char *cmd = argc > 1 ? argv[1] : "version";
|
||||||
int multiple = 0, window = 0, save = 0;
|
int multiple = 0, window = 0, save = 0, persist = 1; /* 0=none 1=transitorio 2=persistente */
|
||||||
for (int i = 2; i < argc; i++) {
|
for (int i = 2; i < argc; i++) {
|
||||||
if (!strcmp(argv[i], "--multiple")) multiple = 1;
|
if (!strcmp(argv[i], "--multiple")) multiple = 1;
|
||||||
else if (!strcmp(argv[i], "--window")) window = 1;
|
else if (!strcmp(argv[i], "--window")) window = 1;
|
||||||
else if (!strcmp(argv[i], "--save")) save = 1;
|
else if (!strcmp(argv[i], "--save")) save = 1;
|
||||||
else if (!strcmp(argv[i], "--wait") && i + 1 < argc) g_wait_s = atoi(argv[++i]);
|
else if (!strcmp(argv[i], "--wait") && i + 1 < argc) g_wait_s = atoi(argv[++i]);
|
||||||
|
else if (!strcmp(argv[i], "--persist") && i + 1 < argc) persist = atoi(argv[++i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBusError err; dbus_error_init(&err);
|
DBusError err; dbus_error_init(&err);
|
||||||
@@ -472,11 +484,11 @@ int main(int argc, char **argv)
|
|||||||
probe_version(bus, "org.freedesktop.portal.Access");
|
probe_version(bus, "org.freedesktop.portal.Access");
|
||||||
probe_version(bus, "org.freedesktop.portal.RemoteDesktop");
|
probe_version(bus, "org.freedesktop.portal.RemoteDesktop");
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else if (!strcmp(cmd, "screencast")) rc = do_screencast(bus, multiple, window);
|
} else if (!strcmp(cmd, "screencast")) rc = do_screencast(bus, multiple, window, persist);
|
||||||
else if (!strcmp(cmd, "filechooser")) rc = do_filechooser(bus, save);
|
else if (!strcmp(cmd, "filechooser")) rc = do_filechooser(bus, save);
|
||||||
else if (!strcmp(cmd, "screenshot")) rc = do_screenshot(bus);
|
else if (!strcmp(cmd, "screenshot")) rc = do_screenshot(bus);
|
||||||
else {
|
else {
|
||||||
fprintf(stderr, "uso: portal-probe {version|screencast|filechooser|screenshot} [--multiple|--window|--save] [--wait N]\n");
|
fprintf(stderr, "uso: portal-probe {version|screencast|filechooser|screenshot} [--multiple|--window|--save] [--wait N] [--persist 0|1|2]\n");
|
||||||
rc = 2;
|
rc = 2;
|
||||||
}
|
}
|
||||||
printf("\n== portal-probe %s: %s ==\n", cmd, rc == 0 ? "OK" : "FALLÓ");
|
printf("\n== portal-probe %s: %s ==\n", cmd, rc == 0 ? "OK" : "FALLÓ");
|
||||||
|
|||||||
Reference in New Issue
Block a user