This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git


The following commit(s) were added to refs/heads/master by this push:
     new ab867b4bc tcp_console: Fix race condition
ab867b4bc is described below

commit ab867b4bc21336a6471ec01c88ce285a45f01a7b
Author: Jerzy Kasenberg <[email protected]>
AuthorDate: Mon Sep 26 22:44:03 2022 +0200

    tcp_console: Fix race condition
    
    tcp_console_flush was being called from main task
    via tx_flush_event and from tcpip task that called
    tcp_console_writable.
    It this happened at the same time tcp_console_out_buf
    could be double freed.
    
    Now flushing happens only from tcpip task and tcp_console_out_buf
    is handed over to tcpip thread in critical section to prevent
    race.
---
 sys/console/full/tcp_console/src/tcp_console.c | 73 ++++++++++++++------------
 1 file changed, 38 insertions(+), 35 deletions(-)

diff --git a/sys/console/full/tcp_console/src/tcp_console.c 
b/sys/console/full/tcp_console/src/tcp_console.c
index f2b4fad80..aaf8fc76e 100644
--- a/sys/console/full/tcp_console/src/tcp_console.c
+++ b/sys/console/full/tcp_console/src/tcp_console.c
@@ -21,57 +21,67 @@
 
 #include <console/console.h>
 #include <mn_socket/mn_socket.h>
+#include "lwip/tcpip.h"
 
 static struct os_event rx_receive_event;
-static struct os_event tx_flush_event;
-struct os_mbuf *tcp_console_out_buf;
+
+static struct os_mbuf *tcp_console_out_buf;
+static struct os_mbuf *flushing_buf;
 
 static struct mn_socket *server_socket;
 static struct mn_socket *console_socket;
 
 static void
-tcp_console_flush(void)
+tcp_console_flush_cb(void *ctx)
 {
+    int sr;
     int rc;
 
-    if (tcp_console_out_buf != NULL && console_socket != NULL) {
-        rc = mn_sendto(console_socket, tcp_console_out_buf, NULL);
-        /* If data was sent, forget about buffer, otherwise keep buffer
-         * and add more data into it */
-        if (rc == 0) {
-            tcp_console_out_buf = NULL;
+    if (flushing_buf == NULL && tcp_console_out_buf != NULL) {
+        OS_ENTER_CRITICAL(sr);
+        flushing_buf = tcp_console_out_buf;
+        tcp_console_out_buf = NULL;
+        OS_EXIT_CRITICAL(sr);
+    }
+    if (flushing_buf != NULL && console_socket != NULL) {
+        rc = mn_sendto(console_socket, flushing_buf, NULL);
+        if (rc) {
+            os_mbuf_free_chain(flushing_buf);
         }
+        flushing_buf = NULL;
     }
 }
 
 static void
 tcp_console_schedule_tx_flush(void)
 {
-    os_eventq_put(os_eventq_dflt_get(), &tx_flush_event);
+    tcpip_try_callback(tcp_console_flush_cb, NULL);
 }
 
 static void
 tcp_console_write(int c)
 {
     uint8_t buf[1] = { (uint8_t)c };
-
-    /* If current mbuf was full, try to send it to client */
-    if (tcp_console_out_buf != NULL && 
OS_MBUF_TRAILINGSPACE(tcp_console_out_buf) == 0) {
-        tcp_console_flush();
-        /*
-         * This may not succeed it socket is not writable yet, mbuf will be 
still present
-         * and additional data will be appended.
-         */
-    }
-    if (tcp_console_out_buf == NULL) {
-        tcp_console_out_buf = os_msys_get_pkthdr(0, 0);
+    struct os_mbuf *mbuf;
+    int sr;
+    bool flush;
+
+    OS_ENTER_CRITICAL(sr);
+    mbuf = tcp_console_out_buf;
+    tcp_console_out_buf = NULL;
+    OS_EXIT_CRITICAL(sr);
+    if (NULL == mbuf) {
+        mbuf = os_msys_get_pkthdr(0, 0);
+        if (NULL == mbuf) {
+            return;
+        }
     }
-
-    os_mbuf_append(tcp_console_out_buf, buf, 1);
-
-    /* If mbuf was just filled up try to send it to client. */
-    if (OS_MBUF_TRAILINGSPACE(tcp_console_out_buf) == 0) {
-        tcp_console_flush();
+    /* If current mbuf was full, try to send it to client */
+    flush = OS_MBUF_TRAILINGSPACE(mbuf) < 2;
+    os_mbuf_append(mbuf, buf, 1);
+    tcp_console_out_buf = mbuf;
+    if (flush) {
+        tcp_console_schedule_tx_flush();
     }
 }
 
@@ -100,12 +110,6 @@ console_rx_restart(void)
     os_eventq_put(os_eventq_dflt_get(), &rx_receive_event);
 }
 
-static void
-tx_flush_ev_cb(struct os_event *ev)
-{
-    tcp_console_flush();
-}
-
 static void
 rx_ev_cb(struct os_event *ev)
 {
@@ -139,7 +143,7 @@ static void
 tcp_console_writable(void *arg, int err)
 {
     if (err == 0) {
-        tcp_console_flush();
+        tcp_console_flush_cb(NULL);
     }
 }
 
@@ -170,7 +174,6 @@ tcp_console_pkg_init(void)
     int rc;
 
     rx_receive_event.ev_cb = rx_ev_cb;
-    tx_flush_event.ev_cb = tx_flush_ev_cb;
 
     /* Create normal TCP socket */
     rc = mn_socket(&server_socket, MN_PF_INET, MN_SOCK_STREAM, 0);

Reply via email to