`
灵动的水
  • 浏览: 194632 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

LINUX下的getifaddrs()函数的内存释放问题

阅读更多
LINUX下的getifaddrs()函数的内存释放问题
在LINUX下获取网卡信息需要用到IOCTL或者getifaddrs
而我在用getifaddrs的时候遇到了内存方面的问题

先看相关定义:
==========

函数定义:
/* Create a linked list of `struct ifaddrs' structures, one for each
   network interface on the host machine.  If successful, store the
   list in *IFAP and return 0.  On errors, return -1 and set `errno'.

   The storage returned in *IFAP is allocated dynamically and can
   only be properly freed by passing it to `freeifaddrs'.  */
extern int getifaddrs (struct ifaddrs **__ifap) __THROW;

/* Reclaim the storage allocated by a previous `getifaddrs' call.  */
extern void freeifaddrs (struct ifaddrs *__ifa)  __THROW;
==============
此函数需要的结构体定义:

struct ifaddrs
{
  struct ifaddrs *ifa_next;     /* Pointer to the next structure.  */

  char *ifa_name;               /* Name of this network interface.  */
  unsigned int ifa_flags;       /* Flags as from SIOCGIFFLAGS ioctl.  */

  struct sockaddr *ifa_addr;    /* Network address of this interface.  */
  struct sockaddr *ifa_netmask; /* Netmask of this interface.  */
  union
  {
    /* At most one of the following two is valid.  If the IFF_BROADCAST
       bit is set in `ifa_flags', then `ifa_broadaddr' is valid.  If the
       IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
       It is never the case that both these bits are set at once.  */
    struct sockaddr *ifu_broadaddr; /* Broadcast address of this interface. */
    struct sockaddr *ifu_dstaddr; /* Point-to-point destination address.  */
  } ifa_ifu;
  /* These very same macros are defined by <net/if.h> for `struct ifaddr'.
     So if they are defined already, the existing definitions will be fine.  */
# ifndef ifa_broadaddr
#  define ifa_broadaddr ifa_ifu.ifu_broadaddr
# endif
# ifndef ifa_dstaddr
#  define ifa_dstaddr   ifa_ifu.ifu_dstaddr
# endif

  void *ifa_data;               /* Address-specific data (may be unused).  */
};
=============
我在调用了getifaddrs()之后,正常地完成了需要的工作
但是最后如果用freeifaddrs,则出现运行时错误
*** glibc detected *** d: free(): invalid pointer: 0x0804a4d4 ***
======= Backtrace: =========
/lib/libc.so.6[0xb7eda911]
/lib/libc.so.6(__libc_free+0x84)[0xb7edbf84]
/lib/libc.so.6(freeifaddrs+0x1d)[0xb7f512dd]
d[0x8048989]
d[0x80486a5]
/lib/libc.so.6(__libc_start_main+0xdc)[0xb7e8c87c]
d[0x8048491]
======= Memory map: ========
08048000-08049000 r-xp 00000000 03:07 48637 /home/souldump/bin/d
08049000-0804a000 rw-p 00000000 03:07 48637 /home/souldump/bin/d
0804a000-0806b000 rw-p 0804a000 00:00 0 [heap]
b7d00000-b7d21000 rw-p b7d00000 00:00 0
b7d21000-b7e00000 ---p b7d21000 00:00 0
b7e76000-b7e77000 rw-p b7e76000 00:00 0
b7e77000-b7f90000 r-xp 00000000 03:05 16184 /lib/libc-2.4.so
b7f90000-b7f92000 r--p 00118000 03:05 16184 /lib/libc-2.4.so
b7f92000-b7f94000 rw-p 0011a000 03:05 16184 /lib/libc-2.4.so
b7f94000-b7f98000 rw-p b7f94000 00:00 0
b7fab000-b7fb5000 r-xp 00000000 03:05 20108 /lib/libgcc_s.so.1
b7fb5000-b7fb6000 rw-p 00009000 03:05 20108 /lib/libgcc_s.so.1
b7fb6000-b7fb7000 rw-p b7fb6000 00:00 0
b7fb7000-b7fd1000 r-xp 00000000 03:05 16177 /lib/ld-2.4.so
b7fd1000-b7fd3000 rw-p 00019000 03:05 16177 /lib/ld-2.4.so
bfb2b000-bfb41000 rw-p bfb2b000 00:00 0 [stack]
ffffe000-fffff000 ---p 00000000 00:00 0 [vdso]

实际上也有人出现相同问题:
http://p.g.yupoo.com/nph-proxy.cgi/000110A/http/www.linuxdby.com/bbs/viewthread.php=3ftid=3d10756
此人说:"这说明不是真正的链表,指针非法"
但是又没有进一步说明怎么解决
他干脆没有调用freeifaddrs,自然会内存泄漏.....

我去看了afaddrs.c
freeifaddrs的定义居然是:
void
freeifaddrs (struct ifaddrs *ifa)
{
free (ifa);
}
怎么样,很囧吧,明明在头文件里说"必须用freeifaddrs才能正确free..."
然后我看了一下getifaddrs的函数体

他在getifaddrs内部定义了一个结构
struct ifaddrs_storage
{
struct ifaddrs ifa;
union
{
/* Save space for the biggest of the four used sockaddr types and
avoid a lot of casts. */
struct sockaddr sa;
struct sockaddr_ll sl;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} addr, netmask, broadaddr;
char name[IF_NAMESIZE + 1];
};

然后把获取的各网卡信息一个个填充到此结构的struct ifaddrs ifa中,ifa的next值手动设置为下一个struct ifaddrs_storage中的ifa的地址...
这酒是所谓的"伪链表"吧?
这就是我无法正确free掉它的原因?
我究竟要怎么把它free掉?freeifaddrs一运行就运行时错误




LINUX取得本机IP的简单C程序
注意这里用了两个struct ifaddrs



//代码根据UNP和man手册编写
//适用于LINUX/BSD(FreeBSD, MacOS X)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>

int main(void)
{
        struct ifaddrs        *ifc, *ifc1;
        char                ip[64];
        char                nm[64];

        if (0 != getifaddrs(&ifc)) return(-1);
        ifc1 = ifc;

        printf("Iface\tIP address\tNetmask\n");
        for(; NULL != ifc; ifc = (*ifc).ifa_next) {
                printf("%s", (*ifc).ifa_name);
                if (NULL != (*ifc).ifa_addr) {
                        inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_addr))->sin_addr), ip, 64);
                        printf("\t%s", ip);
                } else {
                        printf("\t\t");
                }
                if (NULL != (*ifc).ifa_netmask) {
                        inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_netmask))->sin_addr), nm, 64);
                        printf("\t%s", nm);
                } else {
                        printf("\t\t");
                }
                printf("\n");
        }

        freeifaddrs(ifc1);
        return(0);
}



--------------------------------------------------------------------------------



============原来的============
struct ifaddrs *ifap, *ifaphead, *ifaTmp;
getifaddrs(&ifap);
ifaphead = ifap;
while((ifapTmp = ifap) != NULL)
{
//实际任务代码 
ifap = ifapTmp->ifa_next;
}
freeifaddrs(ifaphead);
=========修改后========
struct ifaddrs *ifap, *ifaphead;
getifaddrs(&ifap);
ifaphead = ifap;
while(ifap != NULL)
{
//实际任务代码 
ifap = ifa_next;
}
freeifaddrs(ifaphead);
==================
仅仅是用了一个ifapTmp来代替ifap做事,区别仅此而已(而且我也忘了一开始为什么要用ifapTmp....)
但是最后都是用了freeifaddrs(ifaphead)啊,并没有传错指针啊????
中间的代码并没有对这段数据做任何修改啊.....

请指教一下,这唯一的区别为什么会造成我原先的代码freeifaddrs失败?谢谢!



ifaphead = ifap;                                //这里用ifaphead保存ifap指针地址
while((ifapTmp = ifap) != NULL)
{
ifap = ifapTmp->ifa_next;                //这里修改了ifap的地址
}
freeifaddrs(ifaphead);                       //由于ifap的地址修改,所以ifaphead已经是无效指针。
分享到:
评论

相关推荐

    Linux 常用C函数

    本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考,涵盖了在Linux环境下编程时经常会遇到的一些关键函数。这些函数是C语言标准库的一部分,同时也是Linux系统调用的基础。下面,我们将深入探讨一些重要...

    解决Android下getifaddrs和freeifaddrs undefined reference 的问题

    `freeifaddrs`则用于释放由`getifaddrs`获取的内存资源。 由于Android NDK中没有提供这两个函数,我们可以通过以下步骤来解决这个问题: 1. **自定义实现**:编写C/C++代码来实现`getifaddrs`和`freeifaddrs`。...

    Linux下手动释放内存

    ### Linux下手动释放内存 在Linux系统中,内存管理是一个重要的方面,特别是在服务器环境中,合理的内存管理能够提高系统的性能和稳定性。本文将详细介绍如何通过命令手动释放Linux系统的内存,并解释这些命令背后...

    Linux C函数参考 内存控制篇.rar

    本资料集主要探讨了Linux环境下C语言的内存控制函数,这些函数在编写高效、安全的C程序时至关重要。 1. `malloc()` 函数:这是最常用的动态内存分配函数,用于向系统申请指定大小的内存空间。其原型为`void* malloc...

    易语言内存释放演示

    例如,当你使用"内存分配"函数为一个数据结构分配内存后,一旦该数据结构不再需要,你应该调用"内存释放"函数来释放对应的内存。不正确地管理内存可能会导致程序崩溃或者运行效率下降。 "子程序1"和"子程序2"可能是...

    linux的getch函数

    linux下实现getch函数

    易语言内存释放

    在易语言内存释放源码中,通常会包含使用这些API函数来实现的示例代码,例如编写一个工具,扫描并显示系统中所有进程的内存使用情况,或者检测特定程序的内存泄漏。这种工具对于调试和优化程序的内存性能非常有用。...

    Linux 常用C函数(中文版)

    本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考指南,以方便开发者查找和理解Linux环境下C语言编程时常用的功能函数。这份资料采用HTML格式,便于在网页浏览器中查看和搜索,利用浏览器的"Ctrl+F...

    Linux下系统函数sdk 及 GCC VI 工具的使用指南

    接下来,GCC(GNU Compiler Collection)是Linux下的主要编译器,支持多种编程语言,如C、C++、Objective-C、Fortran等。GCC不仅负责将源代码转换为可执行文件,还提供了代码优化功能。例如,使用`gcc -o output ...

    linux下函数库

    linux下函数介绍蛮详细的,,函数作用,对应的头文件都是什么,挺好用的

    linux常用C函数(中文版)

    本资料集中的“Linux常用C函数(中文版)”提供了关于在Linux环境下使用C语言编程时常见函数的详细解释,对于学习和理解Linux C编程具有极大的帮助。以下是一些关键知识点的概述: 1. **标准库函数**: - `stdio.h`...

    linux下常用c语言函数(word和pdf)

    本资源提供了两个文档,一个是"linux的c函数(Word版).doc",另一个是"Linux_C_fun.pdf",它们都包含了关于Linux环境下常用C语言函数的详细资料。下面我们将深入探讨这些知识点。 1. **标准库函数**: - `stdio.h`...

    Linux 常用C函数中文版

    以上仅是部分常用C函数的介绍,实际的“Linux常用C函数(中文版)”文档可能包含更详细的函数解释、示例代码和使用技巧,帮助开发者深入理解和使用这些函数,从而更高效地编写Linux下的C程序。学习和熟练掌握这些...

    Linux C函数参考 内存及字符串操作篇

    在Linux系统中,C语言是基础且强大的编程工具,它提供了丰富的函数库来处理内存管理和字符串操作。本篇主要探讨的“Linux C函数参考——内存及字符串操作篇”涵盖了两个核心领域:内存管理和字符串处理。以下是对这...

    Linux函数详解(函数大全)

    内存管理在C语言编程中不可或缺,`malloc`和`free`用于动态分配和释放内存,`calloc`则可以一次性分配并初始化内存,`realloc`用于调整已分配内存的大小。 信号处理函数,如`signal`,允许程序对特定事件(如键盘...

    linux下文件拷贝函数

    本文将深入探讨Linux下的文件拷贝函数,以及如何在实际编程中实现这一功能。 首先,我们需要了解Linux中的基本文件操作接口,它们主要通过标准C库提供的`stdio.h`或`unistd.h`头文件中的函数实现。例如,`fopen()`...

    LinuxC函数库中文手册

    《Linux C函数库中文手册》是一本针对Linux操作系统下C语言编程的重要参考资料,它详尽地阐述了在Linux环境中常用C函数的用法,并且配备了丰富的实例,便于读者理解和掌握。这本书采用CHM(Microsoft Compiled ...

    Linux常用C函数速查(中文版)

    "Linux常用C函数速查(中文版)"是一份非常实用的手册,它包含了大量在Linux环境下进行C语言编程时会用到的关键函数,帮助程序员快速查找并理解这些函数的用途和用法。 1. **标准库函数**:C语言的标准库提供了许多...

    linux模块间函数调用通讯

    本文将详细介绍Linux模块间函数调用的通讯机制,并探讨如何解决在实际开发中遇到的相关问题。 #### 二、符号导出与函数调用 ##### 1. 符号导出 在Linux内核中,为了使一个模块中的函数能够被其他模块调用,我们需要...

Global site tag (gtag.js) - Google Analytics