Navigation

    全志在线开发者论坛

    • Register
    • Login
    • Search
    • Categories
    • Tags
    • 在线文档
    • 社区主页

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

    其它全志芯片讨论区
    xr806 xr872 faq 技术支持
    1
    1
    1435
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • q1215200171
      budbool LV 9 last edited by

      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。如下所示:

      export __CONFIG_LWIP_V1 := n
      

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

      git clone https://git.savannah.gnu.org/git/lwip.git
      

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

      git show 5ceaed291f2c1320d36f9501fadd51923fa1c556
      

      修改内容如下所示:

      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 expired\n"));
      
      1 Reply Last reply Reply Quote Share 0
      • Referenced by  q1215200171 q1215200171 
      • Referenced by  q1215200171 q1215200171 
      • Referenced by  q1215200171 q1215200171 
      • Referenced by  q1215200171 q1215200171 
      • Referenced by  q1215200171 q1215200171 
      • Referenced by  q1215200171 q1215200171 
      • 1 / 1
      • First post
        Last post

      Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

      行为准则 | 用户协议 | 隐私权政策