当发现select引发代码崩溃,有什么方法可以更快的解决呢?
本回答来源全志XR806芯片 select引发崩溃如何解决?
方法 (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"));