XLib возвращает поврежденные результаты для XQueryTree ()? - PullRequest
0 голосов
/ 24 марта 2020

Под Linux / X- Windows Я пытался получить рекурсивный список windows. Моя конечная цель - составить список windows с идентификатором, положением, размерами и названием. Некоторые windows (например, xeyes) не имеют заголовка окна в окне верхнего уровня. Необходимо найти первое дочернее окно, чтобы оно могло быть читаемым человеком.

Так что я закончил писать код для рекурсивной выборки каждого окна. Однако список окон, возвращаемый XQueryTree(), похоже, содержит поврежденные данные - некоторые дочерние идентификаторы окон равны нулю. Таким образом, похоже, что XQueryTree() возвращает неправильное количество дочерних элементов (которое должно соответствовать длине выделенного параметра children_list).

В конечном итоге код , в основном , завершается с BadWindow ошибка. Выполнение его через valgrind показывает конец чтения данных, выделенных XQueryTree().

// COMPILE: gcc -Wall -g recursive_window_count.c -o recursive_window_count  -lX11


#include <stdio.h> 
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

#define MAX_INDENT 100

unsigned int getWindowCount( Display *display, Window parent_window, int depth )
{
    Window  root_return;
    Window  parent_return;
    Window *children_list = NULL;
    unsigned int list_length = 0;
    char    indent[MAX_INDENT+1];

    // Make some indentation space, depending on the depth
    memset( indent, '\0', MAX_INDENT+1 );
    for ( int i=0; i<depth*4 && i<MAX_INDENT; i++ )
    {
        indent[i] = ' ';
    }

    // query the window list recursively, until each window reports no sub-windows
    printf( "getWindowCount() - %sWindow %lu\n", indent, parent_window );
    if ( 0 != XQueryTree( display, parent_window, &root_return, &parent_return, &children_list, &list_length ) )
    {
        printf( "getWindowCount() - %s    %d window handle returned\n", indent, list_length );
        if ( list_length > 0 && children_list != NULL )
        {
            for ( int i=0; i<list_length; i++)
            {
                // But typically the "top-level" window is not what the user sees, so query any children
                // Only the odd window has child-windows.  XEyes does.
                if ( children_list[i] != 0 )
                {
                    unsigned int child_length = getWindowCount( display, children_list[i], depth+1 );
                    list_length += child_length;  
                }
                else
                {
                    // There's some weirdness with the returned list
                    // We should not have to be doing this at all
                    printf( "%sHuh? child window handle at index #%d (of %d) is zero?\n", indent, i, list_length );
                    break;  
                }
            }

            XFree( children_list ); // cleanup
        }
    }

    return list_length; 
}


int main( int argc, char **argv )
{
    Display *display;
    Window   root_window;

    display = XOpenDisplay( NULL );
    if ( display ) 
    {
        // Get the number of screens, it's not always one!
        int screen_count = XScreenCount( display );

        // Each screen has a root window
        printf( "There are %d screens available on this X Display\n", screen_count );

        for ( int i=0; i < screen_count; i++ )
        {
            root_window = XRootWindow( display, i );
            printf( "Screen %d - %u windows\n", i, getWindowCount( display, root_window, 0 ) );
        }
        XCloseDisplay( display );
    }

    return 0;
}

Заголовок valgrind журнала:

prompt> valgrind ./recursive_window_count 
==5117== Memcheck, a memory error detector
==5117== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5117== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5117== Command: ./recursive_window_count
==5117== 
There are 1 screen available on this X Display
getWindowCount() - Window 625
getWindowCount() -     105 window handles returned
getWindowCount() -     Window 48234747
getWindowCount() -         1 window handle returned
getWindowCount() -         Window 75497478
getWindowCount() -             1 window handle returned
getWindowCount() -             Window 75497479
getWindowCount() -                 0 window handles returned
==5117== Invalid read of size 8
==5117==    at 0x1093CD: getWindowCount (recursive_window_count.c:38)
==5117==    by 0x109406: getWindowCount (recursive_window_count.c:40)
==5117==    by 0x109530: main (recursive_window_count.c:77)
==5117==  Address 0x4bff508 is 0 bytes after a block of size 8 alloc'd
==5117==    at 0x483A723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==5117==    by 0x483D017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==5117==    by 0x489A53B: XQueryTree (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==5117==    by 0x10934D: getWindowCount (recursive_window_count.c:29)
==5117==    by 0x109406: getWindowCount (recursive_window_count.c:40)
==5117==    by 0x109530: main (recursive_window_count.c:77)
==5117== 
    Huh? child window handle at index #1 (of 2) is zero?
getWindowCount() -     Window 48236534
getWindowCount() -         1 window handle returned
getWindowCount() -         Window 96468999
getWindowCount() -             1 window handle returned
getWindowCount() -             Window 96469000
getWindowCount() -                 0 window handles returned
    Huh? child window handle at index #1 (of 2) is zero?
... truncated

1 Ответ

1 голос
/ 24 марта 2020

Нет, XQueryTree не возвращает данные мусора. Проблема с вашим кодом. list_length += child_length после рекурсивного вызова getWindowCount не имеет смысла и вызывает неопределенное поведение. Просто удалите эту строку.

Некоторые наблюдения:

    char    indent[MAX_INDENT+1];

    // Make some indentation space, depending on the depth
    memset( indent, '\0', MAX_INDENT+1 );
    for ( int i=0; i<depth*4 && i<MAX_INDENT; i++ )
    {
        indent[i] = ' ';
    }

    // query the window list recursively, until each window reports no sub-windows
    printf( "getWindowCount() - %sWindow %lu\n", indent, parent_window );

Используйте только printf("... %*s%lu\n", depth * 4, "", parent_window) вместо всего этого, и вам не придется заботиться о каких-либо MAX_INDENT.

...