ARMmbed / ARMmbed/mbed-drivers

SerialBase:: _irq_handler() tries to invoke NULL callback

Open
#189 1 comment 0 reactions 0 assignees View on GitHub
bug mirrored
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.