全志XR806芯片 select引发崩溃如何解决?

2024-02-02 16:03:57 浏览数 (3)

1. 问题背景 lwip-1.4.1 版本使用 select 函数后引发崩溃。 内部报错:sock != NULL at line 1296 in src/api/sockets.c

2. 问题描述 在多线程同时使用 lwip-1.4.1 版本的 select 函数,可能产生崩溃问题。

3. 问题分析 lwip-1.4.1 中 lwip_select 函数获取 sock 结构时,未对空指针进行处理,从而引发崩溃。多线程操作同个 socket 的场景下易复现该问题。 该 bug 在 lwip 后续版本中进行了修复。

4. 解决办法

方法 (1): 使用 lwip-2.0.3 因为 lwip-2.0.3 中已修复该 bug,切换使用即可。 xradio_skylark_sdk 中切换使用 lwip-2.0.3 的方法:在本地工程的 gcc/localconfig.mk 内部导出 __CONFIG_LWIP_V1 为 n。如下所示:

代码语言:javascript复制
export __CONFIG_LWIP_V1 := n

方法 (2): 合入 lwip 修复成果至 lwip-1.4.1 lwip 开源代码获取方式:

代码语言:javascript复制
git clone https://git.savannah.gnu.org/git/lwip.git

该 bug 在提交 5ceaed291f2c1320d36f9501fadd51923fa1c556 中修复,查看修改的代码:

代码语言:javascript复制
git show 5ceaed291f2c1320d36f9501fadd51923fa1c556

修改内容如下所示:

代码语言:javascript复制
commit 5ceaed291f2c1320d36f9501fadd51923fa1c556
Author: sg <goldsimon@gmx.de>
Date:   Sat Jan 17 21:02:58 2015  0100

    fixed bug #43361 select() crashes with stale FDs

diff --git a/CHANGELOG b/CHANGELOG
index 2c9aebbb..3bf40441 100644
--- a/CHANGELOG
    b/CHANGELOG
@@ -152,6  152,9 @@ HISTORY

      Bugfixes:

   2015-01-17: Simon Goldschmidt
   * sockets.c: fixed bug #43361 select() crashes with stale FDs
 
   2015-01-17: Simon Goldschmidt
   * sockets.c/.h, memp_std.h: fixed bug #40788 "lwip_setsockopt_internal() crashes"
     by rewriting set/getsockopt functions to combine checks with the actual code
diff --git a/src/api/sockets.c b/src/api/sockets.c
index 3369c6d1..4109cee4 100644
--- a/src/api/sockets.c
    b/src/api/sockets.c
@@ -1209,6  1209,7 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
   u32_t msectimeout;
   struct lwip_select_cb select_cb;
   int i;
   int maxfdp2;
   SYS_ARCH_DECL_PROTECT(lev);

   LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")n",
@@ -1266,47  1267,69 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
     SYS_ARCH_UNPROTECT(lev);

     /* Increase select_waiting for each socket we are interested in */
-    for(i = 0; i < maxfdp1; i  ) {
     maxfdp2 = maxfdp1;
     for (i = 0; i < maxfdp1; i  ) {
       if ((readset && FD_ISSET(i, readset)) ||
           (writeset && FD_ISSET(i, writeset)) ||
           (exceptset && FD_ISSET(i, exceptset))) {
-        struct lwip_sock *sock = tryget_socket(i);
-        LWIP_ASSERT("sock != NULL", sock != NULL);
         struct lwip_sock *sock;
         SYS_ARCH_PROTECT(lev);
-        sock->select_waiting  ;
-        LWIP_ASSERT("sock->select_waiting overflow", sock->select_waiting > 0);
         sock = tryget_socket(i);
         if (sock != NULL) {
           sock->select_waiting  ;
           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
         } else {
           /* Not a valid socket */
           nready = -1;
           maxfdp2 = i;
           SYS_ARCH_UNPROTECT(lev);
           break;
         }
         SYS_ARCH_UNPROTECT(lev);
       }
     }

-    /* Call lwip_selscan again: there could have been events between
-       the last scan (without us on the list) and putting us on the list! */
-    nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
-    if (!nready) {
-      /* Still none ready, just wait to be woken */
-      if (timeout == 0) {
-        /* Wait forever */
-        msectimeout = 0;
-      } else {
-        msectimeout =  ((timeout->tv_sec * 1000)   ((timeout->tv_usec   500)/1000));
-        if (msectimeout == 0) {
-          /* Wait 1ms at least (0 means wait forever) */
-          msectimeout = 1;
     if (nready >= 0) {
       /* Call lwip_selscan again: there could have been events between
          the last scan (without us on the list) and putting us on the list! */
       nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset);
       if (!nready) {
         /* Still none ready, just wait to be woken */
         if (timeout == 0) {
           /* Wait forever */
           msectimeout = 0;
         } else {
           msectimeout =  ((timeout->tv_sec * 1000)   ((timeout->tv_usec   500)/1000));
           if (msectimeout == 0) {
             /* Wait 1ms at least (0 means wait forever) */
             msectimeout = 1;
           }
         }
-      }

-      waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
         waitres = sys_arch_sem_wait(SELECT_SEM_PTR(select_cb.sem), msectimeout);
       }
     }
-    /* Increase select_waiting for each socket we are interested in */
-    for(i = 0; i < maxfdp1; i  ) {
 
     /* Decrease select_waiting for each socket we are interested in */
     for (i = 0; i < maxfdp2; i  ) {
       if ((readset && FD_ISSET(i, readset)) ||
           (writeset && FD_ISSET(i, writeset)) ||
           (exceptset && FD_ISSET(i, exceptset))) {
-        struct lwip_sock *sock = tryget_socket(i);
-        LWIP_ASSERT("sock != NULL", sock != NULL);
         struct lwip_sock *sock;
         SYS_ARCH_PROTECT(lev);
-        LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
-        sock->select_waiting--;
         sock = tryget_socket(i);
         if (sock != NULL) {
           /* @todo: what if this is a new socket (reallocated?) in this case,
              select_waiting-- would be wrong (a global 'sockalloc' counter,
              stored per socket could help) */
           LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0);
           if (sock->select_waiting > 0) {
             sock->select_waiting--;
           }
         } else {
           /* Not a valid socket */
           nready = -1;
         }
         SYS_ARCH_UNPROTECT(lev);
       }
     }
@@ -1330,6  1353,12 @@ lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
     sys_sem_free(&select_cb.sem);
 #endif /* LWIP_NETCONN_SEM_PER_THREAD */

     if (nready < 0) {
       /* This happens when a socket got closed while waiting */
       set_errno(EBADF);
       return -1;
     }
 
     if (waitres == SYS_ARCH_TIMEOUT) {
       /* Timeout */
       LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expiredn"));

原贴链接:https://bbs.aw-ol.com/topic/727

0 人点赞