Skip to content

Commit c8772cf

Browse files
Make HardwareSerial::begin() and end() interrupt safe and disable TX/RX if we can't allocate a buffer for them.
Prior to this change, the interrupt could fire during initialisation, necessitating a deep check that the HardwareSerial structure had valid _tx_buffer or _rx_buffer each time an interrupt occurred. By keeping uart_t's and HardwareSerial's (txEnabled, _tx_buffer) and (rxEnabled, _rx_buffer) in sync, we can remove this extra check, as well as fixing a null pointer dereference if e.g. _tx_buffer allocation failed and write() was subsequently called.
1 parent cfe7ae1 commit c8772cf

File tree

1 file changed

+31
-19
lines changed

1 file changed

+31
-19
lines changed

cores/esp8266/HardwareSerial.cpp

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ void uart_disarm_tx_interrupt(uart_t* uart);
101101
void uart_set_baudrate(uart_t* uart, int baud_rate);
102102
int uart_get_baudrate(uart_t* uart);
103103

104-
uart_t* uart_init(int uart_nr, int baudrate, byte config);
104+
uart_t* uart_start_init(int uart_nr, int baudrate, byte config);
105+
void uart_finish_init(uart_t* uart);
105106
void uart_uninit(uart_t* uart);
106107
void uart_swap(uart_t* uart);
107108

@@ -273,9 +274,8 @@ int uart_get_baudrate(uart_t* uart) {
273274
return uart->baud_rate;
274275
}
275276

276-
uart_t* uart_init(int uart_nr, int baudrate, byte config, byte mode) {
277+
uart_t* uart_start_init(int uart_nr, int baudrate, byte config, byte mode) {
277278

278-
uint32_t conf1 = 0x00000000;
279279
uart_t* uart = (uart_t*) os_malloc(sizeof(uart_t));
280280

281281
if(uart == 0) {
@@ -311,6 +311,12 @@ uart_t* uart_init(int uart_nr, int baudrate, byte config, byte mode) {
311311
uart_set_baudrate(uart, baudrate);
312312
USC0(uart->uart_nr) = config;
313313

314+
return uart;
315+
}
316+
317+
void uart_finish_init(uart_t* uart) {
318+
uint32_t conf1 = 0x00000000;
319+
314320
uart_flush(uart);
315321
uart_interrupt_enable(uart);
316322

@@ -323,8 +329,6 @@ uart_t* uart_init(int uart_nr, int baudrate, byte config, byte mode) {
323329
}
324330

325331
USC1(uart->uart_nr) = conf1;
326-
327-
return uart;
328332
}
329333

330334
void uart_uninit(uart_t* uart) {
@@ -485,31 +489,45 @@ HardwareSerial::HardwareSerial(int uart_nr) :
485489
}
486490

487491
void HardwareSerial::begin(unsigned long baud, byte config, byte mode) {
492+
InterruptLock il;
488493

489494
// disable debug for this interface
490495
if(uart_get_debug() == _uart_nr) {
491496
uart_set_debug(UART_NO);
492497
}
493498

494-
_uart = uart_init(_uart_nr, baud, config, mode);
499+
if (_uart) {
500+
os_free(_uart);
501+
}
502+
_uart = uart_start_init(_uart_nr, baud, config, mode);
495503

496504
if(_uart == 0) {
497505
return;
498506
}
499507

500-
if(_uart->rxEnabled) {
501-
if(!_rx_buffer)
502-
_rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE);
508+
// Disable the RX and/or TX functions if we fail to allocate circular buffers.
509+
// The user can confirm they are enabled with isRxEnabled() and isTxEnabled().
510+
if(_uart->rxEnabled && !_rx_buffer) {
511+
_rx_buffer = new cbuf(SERIAL_RX_BUFFER_SIZE);
512+
if(!_rx_buffer) {
513+
_uart->rxEnabled = false;
514+
}
503515
}
504-
if(_uart->txEnabled) {
505-
if(!_tx_buffer)
506-
_tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE);
516+
if(_uart->txEnabled && !_tx_buffer) {
517+
_tx_buffer = new cbuf(SERIAL_TX_BUFFER_SIZE);
518+
if(!_tx_buffer) {
519+
_uart->txEnabled = false;
520+
}
507521
}
508522
_written = false;
509523
delay(1);
524+
525+
uart_finish_init(_uart);
510526
}
511527

512528
void HardwareSerial::end() {
529+
InterruptLock il;
530+
513531
if(uart_get_debug() == _uart_nr) {
514532
uart_set_debug(UART_NO);
515533
}
@@ -660,16 +678,10 @@ HardwareSerial::operator bool() const {
660678
}
661679

662680
void ICACHE_RAM_ATTR HardwareSerial::_rx_complete_irq(char c) {
663-
if(_rx_buffer) {
664-
_rx_buffer->write(c);
665-
}
681+
_rx_buffer->write(c);
666682
}
667683

668684
void ICACHE_RAM_ATTR HardwareSerial::_tx_empty_irq(void) {
669-
if(_uart == 0)
670-
return;
671-
if(_tx_buffer == 0)
672-
return;
673685
const int uart_nr = _uart->uart_nr;
674686
size_t queued = _tx_buffer->getSize();
675687
if(!queued) {

0 commit comments

Comments
 (0)