跳转至内容
  • 版块
  • 最新
  • 标签
  • 热门
折叠
品牌标识

YunTu Forum

YTMicro.com
  1. 主页
  2. Discussion & Question
  3. YT MCAL
  4. MC芯片使用MCAL发现CAN外设的Can_Lld_ReceiveOneFrame函数存在bug

MC芯片使用MCAL发现CAN外设的Can_Lld_ReceiveOneFrame函数存在bug

已定时 已固定 已锁定 已移动 YT MCAL
2 帖子 2 发布者 38 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • yishui66Y 离线
    yishui66Y 离线
    yishui66
    编写于 最后由 yishui66 编辑
    #1

    一、背景
    CAN FD,DTC=15,实际数据只有8字节,此时一发报文给MCU接收,MCU就会进hardfault,如下:
    3a1de83d-a2c3-4f47-b369-7ac89790870a-e32a0c85347d61e53e7c277772c6545.png

    二、现状
    排查为Can_Lld_ReceiveOneFrame函数中未对Payload配置的大小进行检查就直接取数据(存在数组越界风险),原函数如下:

    CAN_FUNC LOCAL_INLINE void Can_Lld_ReceiveOneFrame(uint32 * Addr, Can_HwHandleType Hrh, const Can_ChannelConfigType *ChConfigPtr)
    {
    	Can_HwType MailBoxInfo;
    	PduInfoType PduInfo;
    #if (CAN_CODE_IDHIT == STD_ON)
    	uint8 ChnLogicId = ChConfigPtr->CanChannelId;
    	uint16 Idhit = CAN_CONST_WHOLE_OF_DBYTE_ALL_TRUE;
    #endif
    	Can_CallbackPtrOfReceiveType Callback;
    	uint32 DlcCode;
    #if (CAN_FD_USAGE == STD_ON)
    	PduLengthType MailBoxDatalength = 0U;
        uint8 PduData[CAN_MAXIM_DATA_LENGTH];
    #else
        uint8 PduData[8];
    #endif
    	Can_HwObjRegionType RegionId = Can_ConfigPtr->CanHohCfgPtr[Hrh].CanHwObjRegionId;
    	const uint32 *RamPtr = Addr;
    	MailBoxInfo.Hoh = Hrh;
    	MailBoxInfo.ControllerId = ChConfigPtr->CanChannelId;
    	MailBoxInfo.CanId = Can_Lld_GetCanFrameId(RamPtr, RegionId);
    	DlcCode = (RamPtr[0] & CAN_MB_HERADER_0_DLC_MASK) >> CAN_MB_HERADER_0_DLC_SHIFT;
    	PduInfo.SduLength = (PduLengthType)Can_Table_DlcToDatalength[(uint8)DlcCode];
    	for(uint8 Index = 0U; Index < (uint8)PduInfo.SduLength; ++Index)
        {
    		PduData[Index] = CAN8_READ((uint32)(&RamPtr[0]) + Can_Table_FrameDataAddr[Index]);
        }
        PduInfo.SduDataPtr = PduData;
    #if (CAN_ENHANCE_FIFO_USAGE == STD_ON) /* Handle Enhanced fifo receive */
    	if(CAN_RX_FIFO_ENHANCE == RegionId)
    	{
    #if (STD_ON == CAN_CODE_IDHIT)
    		Idhit = (uint16)RamPtr[Can_Table_DlcToIdhitOff[DlcCode]] & CAN_ENHANCE_RXFIFO_IDHIT_MASK;
    #endif
    	}
        else
    #endif
    
    #if (CAN_LEGACY_FIFO_USAGE == STD_ON) /* Handle legacy fifo receive */
    	if(CAN_RX_FIFO_LEGACY == RegionId)
    	{
    #if (STD_ON == CAN_CODE_IDHIT)
    		Idhit = (uint16)((RamPtr[0] & CAN_LEGACY_RXFIFO_IDHIT_MASK) >> CAN_LEGACY_RXFIFO_IDHIT_SHIFT);
    #endif
    	}
    	else
    #endif
    
    	{
    		if((uint32)CAN_CSCODE_RX_OVERRUN == ((RamPtr[0] & CAN_MB_HERADER_0_CODE_MASK) >> CAN_MB_HERADER_0_CODE_SHIFT))
    		{	/* CAN_CSCODE_RX_OVERRUN */
    			/* Can module shall raise the runtime error CAN_E_DATALOST in case of "overwrite" or
    			"overrun" event detection.
    			Trace SWS_Can_00395 */
    			Can_Bak_CallDatalost(ChConfigPtr->CanChannelId);
    			if(NULL_PTR != ChConfigPtr->CanCallbackPtr->OverrunCallback)
    			{
    				ChConfigPtr->CanCallbackPtr->OverrunCallback(Hrh);
    			}
    		}
    #if (CAN_FD_USAGE == STD_ON)
    		if(TRUE == ChConfigPtr->FdUsage)
    		{
    			MailBoxDatalength = ChConfigPtr->PayloadConfigPtr-> \
    						MbRegionConfig[RegionId].PayloadSize;
    			if (PduInfo.SduLength > MailBoxDatalength)
    			{
    				PduInfo.SduLength = MailBoxDatalength;
    			}
    		}
    #endif
    		/* Read Timer register to unlock the MB */
    		CAN32_READ(((uint32)Addr & CAN_BASE_ADDR_MASK) + CAN_TIMER_OFFSET32);
    	}
    #if (CAN_CODE_IDHIT == STD_ON)
    	if(NULL_PTR != Can_LocFifoIdhitPtr[ChnLogicId])
    	{
    		*Can_LocFifoIdhitPtr[ChnLogicId] = Idhit;
    	}
    #endif
    	Callback = Can_ConfigPtr->CanReceiveCallback;
        if(NULL_PTR == Callback)
    	{
    		CanIf_RxIndication(&MailBoxInfo, &PduInfo);
    	}
    	else
    	{
    		if(TRUE == Callback(MailBoxInfo.Hoh, MailBoxInfo.CanId, (uint8)(PduInfo.SduLength), PduInfo.SduDataPtr))
    		{
    			CanIf_RxIndication(&MailBoxInfo, &PduInfo);
    		}
    	}
    #if (CAN_CODE_IDHIT == STD_ON)
    	if(NULL_PTR != Can_LocFifoIdhitPtr[ChnLogicId])
    	{
    		*Can_LocFifoIdhitPtr[ChnLogicId] = CAN_CONST_WHOLE_OF_DBYTE_ALL_TRUE;
    	}
    #endif
    } 
    

    83fc5ce4-e252-48a5-a1e7-c300996ad577-8257456443cc897bf700834de1f78a2.png

    ②现修改原函数如下:

    AN_FUNC LOCAL_INLINE void Can_Lld_ReceiveOneFrame(uint32 * Addr, Can_HwHandleType Hrh, const Can_ChannelConfigType *ChConfigPtr)
    {
    	Can_HwType MailBoxInfo;
    	PduInfoType PduInfo;
    #if (CAN_CODE_IDHIT == STD_ON)
    	uint8 ChnLogicId = ChConfigPtr->CanChannelId;
    	uint16 Idhit = CAN_CONST_WHOLE_OF_DBYTE_ALL_TRUE;
    #endif
    	Can_CallbackPtrOfReceiveType Callback;
    	uint32 DlcCode;
    #if (CAN_FD_USAGE == STD_ON)
    	PduLengthType MailBoxDatalength = 0U;
        uint8 PduData[CAN_MAXIM_DATA_LENGTH];
    #else
        uint8 PduData[8];
    #endif
    	Can_HwObjRegionType RegionId = Can_ConfigPtr->CanHohCfgPtr[Hrh].CanHwObjRegionId;
    	const uint32 *RamPtr = Addr;
    	MailBoxInfo.Hoh = Hrh;
    	MailBoxInfo.ControllerId = ChConfigPtr->CanChannelId;
    	MailBoxInfo.CanId = Can_Lld_GetCanFrameId(RamPtr, RegionId);
    	DlcCode = (RamPtr[0] & CAN_MB_HERADER_0_DLC_MASK) >> CAN_MB_HERADER_0_DLC_SHIFT;
    	PduInfo.SduLength = (PduLengthType)Can_Table_DlcToDatalength[(uint8)DlcCode];
    #if (CAN_FD_USAGE == STD_ON)
    	if(TRUE == ChConfigPtr->FdUsage)
    	{
    			MailBoxDatalength = ChConfigPtr->PayloadConfigPtr->MbRegionConfig[RegionId].PayloadSize;
    
    			// 限制读取长度为Payload和PduData数组长度的最小值
    			if (PduInfo.SduLength > MailBoxDatalength)
    			{
    					PduInfo.SduLength = MailBoxDatalength;
    			}
    			if (PduInfo.SduLength > sizeof(PduData))
    			{
    					PduInfo.SduLength = sizeof(PduData);  // 防止数组越界
    			}
    	}
    #endif
    	for(uint8 Index = 0U; Index < (uint8)PduInfo.SduLength; ++Index)
        {
    		PduData[Index] = CAN8_READ((uint32)(&RamPtr[0]) + Can_Table_FrameDataAddr[Index]);
        }
        PduInfo.SduDataPtr = PduData;
    #if (CAN_ENHANCE_FIFO_USAGE == STD_ON) /* Handle Enhanced fifo receive */
    	if(CAN_RX_FIFO_ENHANCE == RegionId)
    	{
    #if (STD_ON == CAN_CODE_IDHIT)
    		Idhit = (uint16)RamPtr[Can_Table_DlcToIdhitOff[DlcCode]] & CAN_ENHANCE_RXFIFO_IDHIT_MASK;
    #endif
    	}
        else
    #endif
    
    #if (CAN_LEGACY_FIFO_USAGE == STD_ON) /* Handle legacy fifo receive */
    	if(CAN_RX_FIFO_LEGACY == RegionId)
    	{
    #if (STD_ON == CAN_CODE_IDHIT)
    		Idhit = (uint16)((RamPtr[0] & CAN_LEGACY_RXFIFO_IDHIT_MASK) >> CAN_LEGACY_RXFIFO_IDHIT_SHIFT);
    #endif
    	}
    	else
    #endif
    
    	{
    		if((uint32)CAN_CSCODE_RX_OVERRUN == ((RamPtr[0] & CAN_MB_HERADER_0_CODE_MASK) >> CAN_MB_HERADER_0_CODE_SHIFT))
    		{	/* CAN_CSCODE_RX_OVERRUN */
    			/* Can module shall raise the runtime error CAN_E_DATALOST in case of "overwrite" or
    			"overrun" event detection.
    			Trace SWS_Can_00395 */
    			Can_Bak_CallDatalost(ChConfigPtr->CanChannelId);
    			if(NULL_PTR != ChConfigPtr->CanCallbackPtr->OverrunCallback)
    			{
    				ChConfigPtr->CanCallbackPtr->OverrunCallback(Hrh);
    			}
    		}
    		/* Read Timer register to unlock the MB */
    		CAN32_READ(((uint32)Addr & CAN_BASE_ADDR_MASK) + CAN_TIMER_OFFSET32);
    	}
    #if (CAN_CODE_IDHIT == STD_ON)
    	if(NULL_PTR != Can_LocFifoIdhitPtr[ChnLogicId])
    	{
    		*Can_LocFifoIdhitPtr[ChnLogicId] = Idhit;
    	}
    #endif
    	Callback = Can_ConfigPtr->CanReceiveCallback;
        if(NULL_PTR == Callback)
    	{
    		CanIf_RxIndication(&MailBoxInfo, &PduInfo);
    	}
    	else
    	{
    		if(TRUE == Callback(MailBoxInfo.Hoh, MailBoxInfo.CanId, (uint8)(PduInfo.SduLength), PduInfo.SduDataPtr))
    		{
    			CanIf_RxIndication(&MailBoxInfo, &PduInfo);
    		}
    	}
    #if (CAN_CODE_IDHIT == STD_ON)
    	if(NULL_PTR != Can_LocFifoIdhitPtr[ChnLogicId])
    	{
    		*Can_LocFifoIdhitPtr[ChnLogicId] = CAN_CONST_WHOLE_OF_DBYTE_ALL_TRUE;
    	}
    #endif
    }
    

    具体变更如下:
    4d9fb25a-9448-4161-9a04-9f6bfed2872f-1751339871252.png
    0640927a-880e-47f4-b929-4b8cc37aedb6-1751339949887.png

    ②或者直接这样修改:
    35188dec-1db3-4696-aaf5-76515f8d1fdd-b5581c930b9ef10da7e6318c56e6877.png
    三、述求
    希望云途大佬能够帮忙评估一下这样修改有无其他影响?
    这两种修改方式哪种会更好一些?是否均可?
    谢谢支持

    1 条回复 最后回复
    0
    • jiankang_wangJ 离线
      jiankang_wangJ 离线
      jiankang_wang
      编写于 最后由 编辑
      #2

      感谢您的反馈!
      这个Bug在解决这个帖子的Issue时被修复掉了,但是最新的驱动还需要一点时间才能release,所以目前建议您修改如下:
      ab87917d-5ba6-4c2e-bd45-8154bdcf0240-image.png
      这样的修改后将先判断数据的有效位数,然后再获取数据,这样就不存在数组越界风险了。


      修改有无其他影响?

      原本驱动也考虑到了数据截断的问题,但没有考虑到可能会存在越界到不可访问的区域。这样的修改于原代码相比较,只是调整了接收数据长度的判断位置,所以不会有其他的影响。

      此外,原本的判断代码是包裹在一个 if~elseif~else 代码块中,用于区分接收到的消息是Legacy FIFO, Enhanced FIFO, 以及 MB,包裹在这个代码块中,是为了避免接收FIFO消息时不必要的判断,所以可以直接将这部分代码一移出代码块。

      这两种修改方式哪种会更好一些?是否均可?

      两种方式中,第一种好一点。因为这样只是发生了数据截断,而第二种方式中,会导致 callback 函数中的报文数据是随机的值,debug起来更难理解。

      1 条回复 最后回复
      1

    • 云途论坛规则/Yuntu Forum Rules

      发帖前请查看

    • YCT离线License申请流程

      帮助没办法联网的电脑使用YCT

    • YT CONFIG TOOL调查问卷

      帮助改进和优化YT CONFIG TOOL,有机会抽取YTM32B1ME0 EVB哦...

    • demo
      14
      can
      9
      lin stack
      6
      yt-link
      5
      adc模块
      3
      vscode
      3
      i2c
      2
      uuid
      2
      Online Users
      YQHY
      YQH
      • 登录

      • 登录或注册以进行搜索。
      • 第一个帖子
        最后一个帖子
      0
      • 版块
      • 最新
      • 标签
      • 热门