一个'\0'产生野指针而引起的死机问题

博客讲述了由于C语言strcpy函数使用不当,导致缺少''终止符而产生的野指针问题。在排查过程中,通过内存监控和代码分析,最终发现McfStdC_strtowstr函数中,参数未正确设置为字符串,导致了死机。修复方案是确保输入参数为包含''的字符串。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 在C函数库函数中有个strcpy函数,它的原型大概如下样子:

char * strcpy(char *dest, const char *src)

{
    assert(dest != NULL && src != NULL);
 char *ret = dest;
 while ((*dest++ = *src++) != '\0');
 return ret;
}

从上述看出两个参数必须是字符串(以'\0'结尾),如果没有'\0'结尾就会导致while循环复制的时侯产生野指针;最近解了一个由此导致的死机的log,分享一下思路。

问题:进我们业务去访问T卡的时候就会死机,刚开始对自己的产品很有信心,因此怀疑该项目的T卡相关的代码有问题;然后我对比测试了一下播放音乐,结果播放音乐没问题,因此否定了我的怀疑;于是只能从我们产品的代码上找原因。

assert的信息如下:

Assert的地方如下:

PUBLIC BOOLEAN Spi_Card_Pal_PwrHook(SPI_CARD_PAL_HANDLE handle, SPI_CARD_PAL_PWR_E onOrOff)

{

 uint32 arg;

// 此模块只提供给Card_spi.c这个协议使用,协议代码本身已经保证该handle的有效性,因此在这里不做特别严的检查

SCI_TRACE_LOW("spi_card_pal.c:Spi_Card_Pal_PwrHook handle =%d ,flag = %d", handle,s_cardSpiPalHd[handle].flag );   

CARD_SPI_PAL_ASSERT(

(handle < CARD_SPI_PAL_SUPPORT_NUM)

&&(TRUE == s_cardSpiPalHd[handle].flag) //assert的地方

于是初步怀疑是句柄handler有问题,想抓一个详细的log把SCI_TRACE_LOW里面的东西打印出来,但信息怎么也打印不出来;后来用下面的函数

SCI_PASSERT(((handle < CARD_SPI_PAL_SUPPORT_NUM)

&&(TRUE == s_cardSpiPalHd[handle].flag)),("handle = %d, flag = %d", handle,s_cardSpiPalHd[handle].flag));

替换CARD_SPI_PAL_ASSERT就能把handle的值打印出来了,果然是handle出问题,变成了一个很大的数了。接着看谁调用Spi_Card_Pal_PwrHook给handle赋值的;发现这个handle是由s_cardHandle 这个变量传进来的。于是在内存中监控s_cardHandle这个值,只要谁改变了这个值就assert。内存监控代码见红色部分:

LOCAL BOOLEAN slot0_OpenProtocol()

{

//SPI_RegCSFunc(CARD_SPI_PORT_2, GPIO_SetSDCS);

s_cardHandle = CARD_SPI_Open(CARD_SPI_PORT_0,CARD_CS0,24000000);

{

//wyq_debug

typedef void (*ON_BM_RAISE) (unsigned long data, unsigned long pc_before_fiq);

extern uint32 BM_getAddress( void );

extern void BM_MonitorAnyAddr (uint32 *bm_addr,

                               uint32 bm_data, // 0xffffffff is a invalid value

                               uint32 bm_mode,     // 0: read; 1: write

                               ON_BM_RAISE bm_callback

                              );

BM_MonitorAnyAddr((uint32)(&s_cardHandle), 0xffffffff, 1, NULL); //内存监控

为什么要加在这里 ,因为s_cardHandle在这里赋初始值的,其他对s_cardHandle的操作都在这段代码之后,而BM_MonitorAnyAddr((uint32)(&s_cardHandle), 0xffffffff, 1, NULL)就是在这之后谁对s_cardHandle进行了变动就死机重启。从死机重启的的堆栈中分析出是

#if (defined SPREAD_PLAT_SC6610) || (defined SPREAD_PLAT_SC6600L) || (defined SPREAD_PLAT_SC6620)

MWCHAR g_mcare_device_udisk[] = {0};

MWCHAR g_mcare_device_sdcard[] = {0};

#endif

MWCHAR McfCmn_GetCardDrv(MVOID)

{

#if (defined SPREAD_PLAT_SC6610) || (defined SPREAD_PLAT_SC6600L) || (defined SPREAD_PLAT_SC6620)

         MCHAR drv_tmp = MMIFILE_E_LETTER;

         McfStdC_strtowstr(&g_mcare_device_sdcard[0], &drv_tmp);

         return g_mcare_device_sdcard[0];

#else

出问题了。McfStdC_strtowstr(&g_mcare_device_sdcard[0], &drv_tmp)这个函数是把一个窄字符串扩展成宽字符串,跟strcpy类似--需要传入两个字符串。问题就出在drv_tmp上,drv_tmp是一个字符而不是字符串,导致没有'\0'结尾,而while循环引用指针的时侯产生野指针引用,从而引起死机。将代码改成如下就好了:

#if (defined SPREAD_PLAT_SC6610) || (defined SPREAD_PLAT_SC6600L) || (defined SPREAD_PLAT_SC6620)

MWCHAR g_mcare_device_udisk[2] = {0};

MWCHAR g_mcare_device_sdcard[2] = {0};

#endif

 

MWCHAR McfCmn_GetCardDrv(MVOID)

{ 

MCHAR drv_tmp[2] = {0, 0};

 drv_tmp[0]= MMIFILE_E_LETTER;

McfStdC_strtowstr(&g_mcare_device_sdcard[0], &drv_tmp);

return g_mcare_device_sdcard[0]; 

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值