Skip to content

Commit 38aec02

Browse files
committed
fix(dxinput): fix property reading and button mapping data processing
logic - Replaced custom uchar array conversion function with C.GoBytes to simplify data copying - Modified get_prop function implementation to first obtain the attribute data size, then read the data completely - Corrected get_prop function parameters and comments; nbytes now indicates byte length rather than item count - Added free_prop_data function to release memory returned by get_prop, preventing memory leaks - Ensured proper release of C-allocated data after calling get_prop to retrieve properties in the Go layer - Removed unused maxBufferLen constant and the old ucharArrayToByte implementation Influence: Input Device Management --- fix(dxinput): 修正属性读取和按钮映射数据处理逻辑 - 使用 C.GoBytes 替代自定义 uchar 数组转换函数简化数据拷贝 - 修改 get_prop 函数实现,先获取属性数据大小,再完整读取数据 - 修正 get_prop 函数参数和注释,nbytes 表示字节长度而非项目数 - 添加 free_prop_data 函数用于释放 get_prop 返回的内存,避免内存泄漏 - 在 Go 层调用 get_prop 获取属性后正确释放 C 分配的数据 - 删除无用的 maxBufferLen 常量和 ucharArrayToByte 旧实现 Influence: 输入设备管理功能
1 parent f24ebfc commit 38aec02

6 files changed

Lines changed: 86 additions & 48 deletions

File tree

dxinput/utils/button_map.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func GetButtonMap(xid uint32, devName string) ([]byte, error) {
2929
}
3030
defer C.free(unsafe.Pointer(cbtnMap))
3131

32-
return ucharArrayToByte(cbtnMap, int(cbtnNum)), nil
32+
return C.GoBytes(unsafe.Pointer(cbtnMap), cbtnNum), nil
3333
}
3434

3535
func SetButtonMap(xid uint32, devName string, btnMap []byte) error {

dxinput/utils/property.c

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

55
#include <stdio.h>
6+
#include <limits.h>
67
#include <pthread.h>
78

89
#include <X11/Xatom.h>
@@ -12,26 +13,29 @@
1213
#include "type.h"
1314
#include "x11_mutex.h"
1415

15-
#define MAX_BUF_LEN 1000
16-
1716
/**
1817
* The return data type if 'char' must be convert to 'int8_t*'
1918
* if 'int' must be convert to 'int32_t*'
2019
* if 'float' must be convert to 'float*'
20+
*
21+
* Returns the property data and sets nbytes to the actual byte length.
22+
* The caller is responsible for calling XFree() on the returned data.
2123
**/
2224
unsigned char*
23-
get_prop(int id, const char* prop, int* nitems)
25+
get_prop(int id, const char* prop, int* nbytes)
2426
{
2527
if (!prop) {
2628
fprintf(stderr, "[get_prop] Empty property for %d\n", id);
2729
return NULL;
2830
}
2931

30-
if (!nitems) {
31-
fprintf(stderr, "[get_prop] Invalid item number for %d\n", id);
32+
if (!nbytes) {
33+
fprintf(stderr, "[get_prop] Invalid nbytes pointer for %d\n", id);
3234
return NULL;
3335
}
3436

37+
*nbytes = 0;
38+
3539
pthread_mutex_lock(&x11_global_mutex);
3640
setErrorHandler();
3741

@@ -54,24 +58,82 @@ get_prop(int id, const char* prop, int* nitems)
5458
int act_format;
5559
unsigned long num_items, bytes_after;
5660
unsigned char* data = NULL;
57-
int ret = XIGetProperty(disp, id, prop_id, 0, MAX_BUF_LEN, False,
61+
62+
// Step 1: Query property size (length=0 to get bytes_after)
63+
int ret = XIGetProperty(disp, id, prop_id, 0, 0, False,
5864
AnyPropertyType, &act_type, &act_format,
5965
&num_items, &bytes_after, &data);
66+
if (ret != Success || act_type == None) {
67+
if (data) {
68+
XFree(data);
69+
}
70+
XCloseDisplay(disp);
71+
pthread_mutex_unlock(&x11_global_mutex);
72+
return NULL;
73+
}
74+
75+
if (data) {
76+
XFree(data);
77+
data = NULL;
78+
}
79+
80+
if (bytes_after == 0) {
81+
// Property exists but has no data
82+
XCloseDisplay(disp);
83+
pthread_mutex_unlock(&x11_global_mutex);
84+
return NULL;
85+
}
86+
87+
// Step 2: Read all property data
88+
// length is in 32-bit units, so divide bytes_after by 4 (round up)
89+
unsigned long length = (bytes_after + 3) / 4;
90+
91+
ret = XIGetProperty(disp, id, prop_id, 0, length, False,
92+
AnyPropertyType, &act_type, &act_format,
93+
&num_items, &bytes_after, &data);
6094
if (ret != Success) {
95+
if (data) {
96+
XFree(data);
97+
}
6198
XCloseDisplay(disp);
6299
fprintf(stderr, "[get_prop] Get %s data failed for %d\n", prop, id);
63100
pthread_mutex_unlock(&x11_global_mutex);
64101
return NULL;
65102
}
66103

67-
*nitems = (int)num_items;
68-
XCloseDisplay(disp);
104+
// Calculate actual byte length based on format and num_items
105+
// format is 8, 16, or 32 bits per item
106+
// Guard against integer overflow when converting unsigned long to int
107+
unsigned long nbytes_ul = num_items * (act_format / 8);
108+
if (nbytes_ul > INT_MAX) {
109+
if (data) {
110+
XFree(data);
111+
}
112+
XCloseDisplay(disp);
113+
fprintf(stderr, "[get_prop] Property data too large: %lu bytes (max %d)\n", nbytes_ul, INT_MAX);
114+
pthread_mutex_unlock(&x11_global_mutex);
115+
return NULL;
116+
}
117+
*nbytes = (int)nbytes_ul;
69118

119+
XCloseDisplay(disp);
70120
pthread_mutex_unlock(&x11_global_mutex);
71121

72122
return data;
73123
}
74124

125+
/**
126+
* Free the property data returned by get_prop.
127+
* This is a wrapper for XFree to be called from Go.
128+
*/
129+
void
130+
free_prop_data(unsigned char* data)
131+
{
132+
if (data) {
133+
XFree(data);
134+
}
135+
}
136+
75137
// bit: range(8,16,32)
76138
int
77139
set_prop_int(int id, const char* prop, unsigned char* data, int nitems, int bit)

dxinput/utils/property.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77

88
#include <X11/Xlib.h>
99

10-
unsigned char* get_prop(int id, const char* prop, int* nitems);
10+
unsigned char* get_prop(int id, const char* prop, int* nbytes);
11+
void free_prop_data(unsigned char* data);
1112
int set_prop_int(int id, const char* prop, unsigned char* data, int nitems, int bit);
1213
int set_prop_float(int id, const char* prop, unsigned char* data, int nitems);
1314
int set_prop(int id, const char* prop, unsigned char* data, int nitems,

dxinput/utils/type.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ listener_error_handler(Display * display, XErrorEvent * event)
3737
int
3838
listener_ioerror_handler(Display * display)
3939
{
40+
(void)display; // Suppress unused parameter warning
4041
return 0;
4142
}
4243

@@ -157,7 +158,7 @@ static int
157158
is_keyboard_device(int deviceid)
158159
{
159160
Display *display;
160-
int num_devices, i;
161+
int num_devices;
161162

162163
// NOTE: No mutex lock here - called from query_device_type which already holds the lock
163164
// 打开 X11 显示

dxinput/utils/wrapper.go

Lines changed: 9 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@ import (
2323
"github.com/linuxdeepin/dde-api/dxinput/kwayland"
2424
)
2525

26-
const (
27-
// see 'property.c' MAX_BUF_LEN
28-
maxBufferLen = 1000
29-
)
30-
3126
func ListDevice() DeviceInfos {
3227
if len(os.Getenv("WAYLAND_DISPLAY")) != 0 {
3328
infos, _ := kwayland.ListDevice()
@@ -103,21 +98,19 @@ func GetProperty(id int32, prop string) ([]byte, int32) {
10398
}
10499

105100
cprop := C.CString(prop)
101+
defer C.free(unsafe.Pointer(cprop))
106102

107-
defer func() {
108-
if cprop != nil {
109-
C.free(unsafe.Pointer(cprop))
110-
}
111-
}()
112-
113-
nitems := C.int(0)
114-
cdatas := C.get_prop(C.int(id), cprop, &nitems)
115-
if cdatas == nil || nitems == 0 {
103+
// nbytes now represents the actual byte length returned by C layer
104+
nbytes := C.int(0)
105+
cdatas := C.get_prop(C.int(id), cprop, &nbytes)
106+
if cdatas == nil || nbytes == 0 {
116107
return nil, 0
117108
}
109+
// XIGetProperty allocates memory for data, caller must free it with XFree
110+
defer C.free_prop_data(cdatas)
118111

119-
datas := ucharArrayToByte(cdatas, maxBufferLen)
120-
return datas, int32(nitems)
112+
datas := C.GoBytes(unsafe.Pointer(cdatas), nbytes)
113+
return datas, int32(nbytes)
121114
}
122115

123116
func SetInt8Prop(id int32, prop string, values []int8) error {
@@ -196,25 +189,6 @@ func SetFloat32Prop(id int32, prop string, values []float32) error {
196189
return nil
197190
}
198191

199-
func ucharArrayToByte(cData *C.uchar, length int) []byte {
200-
if cData == nil {
201-
return nil
202-
}
203-
cItemSize := unsafe.Sizeof(*cData)
204-
205-
var data []byte
206-
for i := 0; i < length; i++ {
207-
offset := uintptr(i) * cItemSize
208-
addr := uintptr(unsafe.Pointer(cData)) + offset
209-
cdata := (*C.uchar)(unsafe.Pointer(addr))
210-
if cdata == nil {
211-
break
212-
}
213-
data = append(data, byte(*cdata))
214-
}
215-
return data
216-
}
217-
218192
func byteArrayToUChar(datas []byte) []C.uchar {
219193
var cdatas []C.uchar
220194
for i := 0; i < len(datas); i++ {

dxinput/wacom.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ package dxinput
66

77
import (
88
"bytes"
9+
"errors"
910
"fmt"
1011
"os/exec"
1112
"strconv"
1213
"strings"
13-
"errors"
1414

1515
. "github.com/linuxdeepin/dde-api/dxinput/common"
1616
"github.com/linuxdeepin/dde-api/dxinput/utils"
@@ -251,7 +251,7 @@ func doAction(cmd string) error {
251251
// #nosec G204
252252
out, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
253253
if err != nil {
254-
return fmt.Errorf(string(out))
254+
return errors.New(string(out))
255255
}
256256
return nil
257257
}

0 commit comments

Comments
 (0)