RT-Thread / RT-Thread/rt-thread

动态模块中未初始化全局变量访问异常

Open
#5,705 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
C
Stars
12.2k
Forks
5.4k
Avg merge
4d 12h
Merged PRs (30d)
40

Description

异常的软硬件环境

软件版本:rt-thread标准版 master分支
bsp型号:qemu-vexpress-a9
硬件环境:qemu-vexpress-a9

出现问题的步骤

参考动态模块使用方法,创建了hello.mo文件;在rt-thread系统启动后,访问hello.mo,在访问hello.mo的全局未初始化指针变量的时候,指针serial的低八位空间被另一个全局变量结构体踩内存了,异常现场如下:

1648087117298_AB2D5721-35D6-4b25-BEEC-58DD41389295

异常时,创建hello.mo的软件代码

/*
 * 程序清单:这是一个 串口 设备使用例程
 * 例程导出了 uart_sample 命令到控制终端
 * 命令调用格式:uart_sample uart2
 * 命令解释:命令第二个参数是要使用的串口设备名称,为空则使用默认的串口设备
 * 程序功能:通过串口输出字符串"hello RT-Thread!",然后错位输出输入的字符
*/
#include <stdio.h>
#include <rtthread.h>

#define BUF_SIZE32
#define SAMPLE_UART_NAME   "uart0"  /* 串口设备名称 */
/* 用于接收消息的信号量 */
static struct rt_semaphore rx_sem;
static rt_device_t serial;

/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
/* 串口接收到数据后产生中断,调用此回调函数,然后发送接收信号量 */
rt_sem_release(&rx_sem);
return RT_EOK;
}

static void serial_thread_entry(void *parameter)
{
static int ret, want;
char *rx_buf = RT_NULL;

	rt_kprintf("[%s,%d], come in.\n", __func__, __LINE__);

rx_buf = rt_malloc(BUF_SIZE);
rt_memset(rx_buf, 0, BUF_SIZE);

while (1)
{
want = BUF_SIZE;
rt_memset(rx_buf, 0, BUF_SIZE);

re_read:
/* 从串口读取的数据,没有读取到则等待接收信号量 */
ret = rt_device_read(serial, 0, rx_buf, want);

/* 读取到的数据通过串口输出 */
if (ret 0)
{
rt_device_write(serial, 0, rx_buf, ret);

if (ret != want)
{
want = want - ret;
goto
re_read;
}
}
else
/* 阻塞等待接收信号量,等到信号量后再次读取数据 */
rt_sem_take(&rx_sem, RT_WAITING_FOREVER);

ret = 0;
}

rt_free(rx_buf);
rx_buf = RT_NULL;
}

int main(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
char uart_name[RT_NAME_MAX];
char str[] = "hello RT-Thread!\r\n";

if (argc == 2)
{
rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
}

/* 查找系统中的串口设备 */
serial = rt_device_find(uart_name);
if (!serial)
{
rt_kprintf("find %s failed!\n", uart_name);
return RT_ERROR;
}

	rt_kprintf("[%s,%d], rx_sem:0x%x.\n",
		__func__, __LINE__, &rx_sem);
	rt_kprintf("[%s,%d], seial(0x%p, size:%d):0x%x.\n",
		__func__, __LINE__, &serial, sizeof(struct rt_device), (unsigned int)serial);

/* 初始化信号量 */
rt_sem_init(&rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
	
	rt_kprintf("[%s,%d], seial(0x%p):0x%x.\n",
		__func__, __LINE__, &serial, (unsigned int)serial);
	
/* 以中断接收及轮询发送模式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
/* 设置接收回调函数 */
rt_device_set_rx_indicate(serial, uart_input);
/* 发送字符串 */
rt_device_write(serial, 0, str, (sizeof(str) - 1));

/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 26, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
ret = RT_ERROR;
}

return ret;
}

出现异常时的疑问

在全局变量rx_sem大小为36个字节,serial指针变量大小为4字节;我们一起来看这两个变量的内存地址分布,rx_sem变量的地址范围为0x6008895c-0x6008897f,serial 的地址为0x6008897c;至此,明显serial指针变量的地址位于rx_sem的变量的地址区间内?这算是动态模块的已知bug嘛?

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue on qemu-vexpress-a9 using the reported hello.mo module and compare the addresses of rx_sem and serial during startup. Inspect the dynamic-module global-variable layout and confirm that the completed fix prevents overlap, allowing the module to access both globals without memory corruption.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
embedded-iot, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.