ARMmbed / ARMmbed/mbed-drivers
SerialBase:: _irq_handler() tries to invoke NULL callback
- Dominant language
- C++
- Stars
- 39
- Forks
- 41
- PR merge metrics
- No merged PRs in 30d
Description
`handler->_irq[irq_type]` can be undefined/nullptr if `SeriaBasel#attach()` is invoked for attaching a callback function to either `Serial::RxIrq` or `Serial::TxIrq`.
[SerialBase.cpp#L62](https://github.com/ARMmbed/mbed-drivers/blob/master/source/SerialBase.cpp#L62)
```
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
SerialBase *handler = (SerialBase*)id;
handler->_irq[irq_type].call();
}
```
Because of lack of the checking, I got an assertion error `(_membercaller != NULL) && (_object != NULL)` at core-util/core-util/FunctionPointerBase.h:68 when UART RX received data and `RawSerial::attach(&some_callbck, Serial::RxIrq)` was called.
Here is a backtrace at that time:
```
#0 0x0800a766 in us_ticker_read () at /path/to/my-workspace/yotta_modules/mbed-hal-st-stm32f4/source/us_ticker.c:48
#1 0x08007694 in wait_us (us=150000) at /path/to/my-workspace/yotta_modules/mbed-drivers/source/wait_api.c:30
#2 0x08007678 in wait_ms (ms=150) at /path/to/my-workspace/yotta_modules/mbed-drivers/source/wait_api.c:25
#3 0x0800828a in mbed_die () at /path/to/my-workspace/yotta_modules/mbed-drivers/source/board.c:59
#4 0x0800a222 in core_util_assert_internal (expr=0x8016c78 "(_membercaller != NULL) && (_object != NULL)",
file=0x8016c10 "/path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointerBase.h", line=68, msg=0x0)
at /path/to/my-workspace/yotta_modules/core-util/source/assert_mbed.c:53
#5 0x08008d82 in mbed::util::FunctionPointerBase::call (this=0x20008844 , arg=0x0)
at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointerBase.h:68
#6 0x08008cae in mbed::util::FunctionPointer0::call (this=0x20008844 ) at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointer.h:84
#7 0x08008bf6 in mbed::SerialBase::_irq_handler (id=536905624, irq_type=TxIrq) at /path/to/my-workspace/yotta_modules/mbed-drivers/source/SerialBase.cpp:64
#8 0x0800b10a in uart_irq (id=0) at /path/to/my-workspace/yotta_modules/mbed-hal-st-stm32f4/source/serial_api.c:442
#9 0x0800b15e in uart1_irq () at /path/to/my-workspace/yotta_modules/mbed-hal-st-stm32f4/source/serial_api.c:486
#10
#11 0x0800ae5a in NVIC_EnableIRQ (IRQn=USART1_IRQn) at /path/to/my-workspace/yotta_modules/cmsis-core/cmsis-core/core_cm4.h:1471
#12 0x0800b23a in serial_irq_set (obj=0x20008800 , irq=RxIrq, enable=1) at /path/to/my-workspace/yotta_modules/mbed-hal-st-stm32f4/source/serial_api.c:753
#13 0x0800762c in mbed::SerialBase::attach (this=0x20008798 , tptr=0x20009660,
mptr=(void (MySerialTest::*)(MySerialTest * const)) 0x80071ed , type=mbed::SerialBase::RxIrq)
at /path/to/my-workspace/yotta_modules/mbed-drivers/mbed-drivers/SerialBase.h:113
#14 0x0800728e in MySerialTest::rs485_txrx_tick (this=0x20009660) at /path/to/my-workspace/source/my_serial_test.cpp:124
#15 0x08003f60 in mbed::util::FunctionPointer0::membercaller (object=0x20009660, member=0x2001793c "Qr", arg=0x20017950)
at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointer.h:108
#16 0x08008d92 in mbed::util::FunctionPointerBase::call (this=0x20017938, arg=0x20017950)
at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointerBase.h:70
#17 0x0800a07e in mbed::util::FunctionPointerBind::call (this=0x20017938) at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointerBind.h:50
#18 0x08009b7e in mbed::util::FunctionPointerBind::operator() (this=0x20017938)
at /path/to/my-workspace/yotta_modules/core-util/core-util/FunctionPointerBind.h:93
#19 0x08009740 in minar::SchedulerData::start (this=0x20009040) at /path/to/my-workspace/yotta_modules/minar/source/minar.cpp:354
#20 0x080093f4 in minar::Scheduler::start () at /path/to/my-workspace/yotta_modules/minar/source/minar.cpp:178
#21 0x08007e68 in main () at /path/to/my-workspace/yotta_modules/mbed-drivers/source/retarget.cpp:559
```
So `SerialBase::_irq_handler` has to check if the callback associated with the `irq_type` exists.
```
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
SerialBase *handler = (SerialBase*)id;
if (handler->_irq[irq_type]) {
handler->_irq[irq_type].call();
}
}
```
By the way, I don't have any idea why Serial::TxIrq was fired though the actual event should be UART RX. This could be the root cause but I don't know if it's true the expected behavior.
mbed-drivers version:
```
"version": "1.5.0",
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in source/SerialBase.cpp at _irq_handler(), using the reported assertion and backtrace to understand when an unset IRQ callback is invoked. Check the SerialBase attach path and existing serial-related tests or reproduction steps; done means an unset callback no longer asserts and the unexpected TxIrq behavior is understood or documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- embedded-iot
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100