RT-Thread / RT-Thread/rt-thread

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

Offen
#5,705 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

bug
Vorherrschende Sprache
C
Sterne
12.2k
Forks
5.4k
Ø Merge
4 T. 12 Std.
Gemergte PRs (30 T.)
40

Beschreibung

异常的软硬件环境

软件版本: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嘛?

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Reproduzieren Sie das Problem auf qemu-vexpress-a9 mit dem gemeldeten hello.mo-Modul und vergleichen Sie während des Starts die Adressen von rx_sem und serial. Untersuchen Sie das Layout der globalen Variablen von dynamic-module und bestätigen Sie, dass der abgeschlossene Fix eine Überlappung verhindert, sodass das Modul auf beide globalen Variablen zugreifen kann, ohne Speicher zu beschädigen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
c
Bereich
embedded-iot, operating-systems
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
35/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.