XLib 为 XQueryTree() 返回损坏的结果?
XLib returning corrupt results for XQueryTree()?
在 Linux / X-Windows 下,我一直在尝试获取 windows 的递归列表。我的最终目标是生成一个包含 ID、位置、尺寸和标题的 windows 列表。一些 windows(例如 xeyes
)在 top-level window 上没有 window 标题。必须找到第一个 child window 才能得到 human-readable window 名称。
所以我最终编写了代码以递归地获取每个 window。然而,XQueryTree()
返回的 window 列表似乎有损坏的数据 - 有些 child window-IDs 为零。所以看起来 XQueryTree()
返回的 children 数量不正确(应该与分配的 children_list
参数的长度匹配)。
最终代码 大部分 失败并出现 BadWindow
错误。 运行 它通过 valgrind
在 XQueryTree()
.
分配的数据中显示 read-past-end
// 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, '[=10=]', 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
不,XQueryTree
没有返回垃圾数据。问题出在您的代码上。递归调用 getWindowCount
之后的 list_length += child_length
没有任何意义,并且会触发未定义的行为。只需删除该行。
一些观察:
char indent[MAX_INDENT+1];
// Make some indentation space, depending on the depth
memset( indent, '[=10=]', 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
.
在 Linux / X-Windows 下,我一直在尝试获取 windows 的递归列表。我的最终目标是生成一个包含 ID、位置、尺寸和标题的 windows 列表。一些 windows(例如 xeyes
)在 top-level window 上没有 window 标题。必须找到第一个 child window 才能得到 human-readable window 名称。
所以我最终编写了代码以递归地获取每个 window。然而,XQueryTree()
返回的 window 列表似乎有损坏的数据 - 有些 child window-IDs 为零。所以看起来 XQueryTree()
返回的 children 数量不正确(应该与分配的 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, '[=10=]', 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
不,XQueryTree
没有返回垃圾数据。问题出在您的代码上。递归调用 getWindowCount
之后的 list_length += child_length
没有任何意义,并且会触发未定义的行为。只需删除该行。
一些观察:
char indent[MAX_INDENT+1];
// Make some indentation space, depending on the depth
memset( indent, '[=10=]', 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
.