簡體   English   中英

getifaddrs 返回“錯誤的文件描述符”/使應用程序崩潰

[英]getifaddrs returning 'bad file descriptor'/crashing the application

在我的程序中,我有一個線程必須持續監視網絡接口,因此它在 while 循環中不斷使用 getifaddrs()。

    while(true) {
    
        struct ifaddrs *ifaddr, *ifa;
        if (getifaddrs(&ifaddr) == -1) {
            perror("getifaddrs couldn't fetch required data");
            exit(EXIT_FAILURE);
        }
  
        //Iterate through interfaces linked list
        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        //monitoring logic
        }

       //Free linked list
       freeifaddrs(ifaddr);

       //Sleep for specified time fo next polling cycle
       usleep(1000);
    
    }

大多數時候我的程序運行良好。 但是,有時 getifaddrs() 返回 -1 和 errNo = EBADF(bad file descriptor) 為了不退出我的線程,我暫時用 continue 替換了 exit(因為我不希望我的程序因此而結束)。 但是,我很想知道在哪些情況下 getifaddrs() 會返回“錯誤文件描述符”錯誤,以及我是否可以采取一些措施避免這種情況發生?

編輯

用“繼續”替換“退出”並沒有解決我的問題。 有時調用 getifaddrs() 會使應用程序崩潰!

下面給出的是使用生成的核心文件從 gdb 獲得的回溯。

Program terminated with signal 6, Aborted.
#0  0x00007fe2df1ef387 in raise () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-307.el7.1.x86_64 keyutils-libs-1.5.8-3.el7.x86_64 krb5-libs-1.15.1-37.el7_6.x86_64 libcom_err-1.42.9-16.el7.x86_64 libgcc-4.8.5-39.el7.x86_64 libselinux-2.5-14.1.el7.x86_64 libstdc++-4.8.5-39.el7.x86_64 openssl-libs-1.0.2k-19.el7.x86_64 pcre-8.32-17.el7.x86_64 zlib-1.2.7-18.el7.x86_64
(gdb) bt
#0  0x00007fe2df1ef387 in raise () from /lib64/libc.so.6
#1  0x00007fe2df1f0a78 in abort () from /lib64/libc.so.6
#2  0x00007fe2df231ed7 in __libc_message () from /lib64/libc.so.6
#3  0x00007fe2df231fbe in __libc_fatal () from /lib64/libc.so.6
#4  0x00007fe2df2df4c2 in __netlink_assert_response () from /lib64/libc.so.6
#5  0x00007fe2df2dc412 in __netlink_request () from /lib64/libc.so.6
#6  0x00007fe2df2dc5ef in getifaddrs_internal () from /lib64/libc.so.6
#7  0x00007fe2df2dd310 in getifaddrs () from /lib64/libc.so.6
#8  0x000000000047c03c in __interceptor_getifaddrs.part.0 ()

操作系統:Red Hat Enterprise Linux 服務器版本 7.8(邁坡)

GLIBC 版本:2.17

根據man7.org getifaddrs ,任何套接字操作都可能是EBADF的原因

錯誤

getifaddrs() 可能會失敗並為 socket(2)、bind(2)、getsockname(2)、recvmsg(2)、sendto(2)、malloc(3) 或 realloc(3) 指定的任何錯誤設置 errno .


不相關,但你在某處做freeifaddrs()嗎?

手冊頁中的以下示例已修改為包含您的忙循環和usleep在 valgrind 下運行了幾分鍾而沒有拋出錯誤; 盡管我的服務器在運行此示例時沒有任何網絡接口出現故障或上線。

我在具有glibc-2.17-323.el7_9.x86_64的 CentOS 7.9 上進行了測試。

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char host[NI_MAXHOST];

    while (1) {
        if (getifaddrs(&ifaddr) == -1) {
            perror("getifaddrs");
            exit(EXIT_FAILURE);
        }

        /* Walk through linked list, maintaining head pointer so we
          can free list later */

        for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
            if (ifa->ifa_addr == NULL)
                continue;
            family = ifa->ifa_addr->sa_family;
            /* Display interface name and family (including symbolic
               form of the latter for the common families) */
            // Commented out
        }
        freeifaddrs(ifaddr);
        usleep(1000);
    }
    exit(EXIT_SUCCESS);
}

有趣的是:GNU 的 glibc-2.17 沒有斷言__netlink_assert_response ,但 GNU 的 glibc-2.31 有。 所以,這是 RedHat 稍后修補的東西(您可以使用重新訪問我的步驟):

SRC=`basename $(rpm -q glibc) .x86_64`.src.rpm
wget --no-check-certificate http://vault.centos.org/7.9.2009/updates/Source/SPackages/${SRC}
CPIO=`basename ${SRC} .rpm`.cpio
rpm2cpio ${SRC} > ${CPIO}
mkdir glibc-src && cd glibc-src
cpio -ivd < ${CPIO}

這表明,在您的情況下失敗的斷言是由 Patch glibc-rh1443872.patch添加的,其中指出:

提交 2eecc8afd02d8c65cf098cbae4de87f332dc21bd

作者: ...

日期:2015 年 11 月 9 日星期一 12:48:41 +0100

終止來自 kernel 的無效網絡鏈接響應的進程 [BZ #12926]

Bugzilla 條目https://sourceware.org/bugzilla/show_bug.cgi?id=12926提供了有關 NetLink 接口有損的詳細信息。

現在所有這些都不能回答你的問題:為什么getifaddrs失敗並且 glibc 用信號SIGABRT殺死你的進程。

就像 [@matthieu] 一樣,假設您沒有在監控邏輯中弄亂您的堆棧和/或指針ifaddr ,這仍然可能是 kernel 和 glibc 之間的通信錯誤,需要進一步調查。 作為一種解決方法,您可能會暫時捕獲中止信號,如如何處理 SIGABRT 信號中所述?

https://patchwork.ozlabs.org/project/netdev/patch/5638B93F.3090202@redhat.com/

在鏈接中它說崩潰的原因是。 “netlink sockets 的 recvmsg 系統調用在文件描述符競爭后特別容易拾取不相關的數據(由於其他地方的文件描述符管理問題,描述符在多線程進程中同時關閉和重新打開)。 ”。

所以我認為你要么不使用單獨的線程,要么在netlink函數周圍使用一些鎖定機制。

當您在主線程中監視網絡接口時,至少只需確認它是否仍然崩潰。

幸運的是,我已經能夠追蹤問題背后的根本原因。 該方案已在此處詳細說明

所以基本上,我程序中的一個線程有這個“雙重關閉”錯誤,有時會導致問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM