`
灵动的水
  • 浏览: 195943 次
  • 性别: 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已经是无效指针。
分享到:
评论

相关推荐

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

    而`freeifaddrs`则用于释放由`getifaddrs`分配的内存资源。 在Android中,由于NDK(Native Development Kit)环境与标准的Linux环境存在差异,`getifaddrs`和`freeifaddrs`可能不在默认的链接库中。因此,当你尝试...

    Linux C函数库参考手册完整版 含Linux C函数使用手册chm 中文pdf格式

    在Linux下,使用到的C语言函数中文手册,全都有实例,如果你是大神,完全不需要,如果你对英文的手册感到头疼,而且是初学者,对很多用到的函数不太熟悉,这个文档对你有很大的帮助。 这里包含了所有的linux下C编程...

    linux下kbhit函数

    linux下面实现kbhit函数

    linux下内存池实现

    本文将深入探讨Linux下的内存池实现,包括其原理、优势以及如何在C或C++中进行实践。 内存池的基本原理是预先一次性申请一大块连续内存,并将其分割成多个固定大小的小块,这些小块被称为内存块或者对象。当程序...

    linux c内存分配函数介绍

    vmalloc函数用于分配虚拟内存,vfree函数用于释放虚拟内存。vmalloc函数的用法与kmalloc函数相似,但是vmalloc函数可以分配更大的内存块。 Linux C中的内存分配函数非常重要,包括malloc, kmalloc, zalloc等等。每...

    Linux 内存泄露查找

    特别是在动态内存分配场景下,如果不妥善处理,很容易出现内存泄露的问题。内存泄露不仅会消耗系统资源,还可能导致应用程序性能下降甚至崩溃。因此,掌握如何有效地检测和定位内存泄露问题显得尤为重要。本文将详细...

    Linux 常用C函数

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

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

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

    linux的getch函数

    linux下实现getch函数

    wince内存释放,wince内存释放

    本文将深入探讨WinCE环境下的内存释放机制,以及如何有效地进行内存管理和优化。 1. WinCE内存管理基础 WinCE内存管理系统采用了一个与Windows NT相似的模型,包括堆、栈和全局数据区等部分。堆是动态分配内存的...

    易语言内存释放

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

    LinuxC常用函数手册

    在Linux环境下进行C语言编程,理解并掌握常用的C库函数是至关重要的。这份"LinuxC常用函数手册"为你提供了一份详尽的参考资料,涵盖了Linux C编程中的基础到高级的函数用法。以下是一些关键的知识点: 1. **标准...

    Linux下的C函数手册CHM版.rar_C函数_chm_linux_linuxc库函数chm_towardopp

    linux开发手册 函数API接口查询 系统调用以及相关库函数的使用说明

    linux常用c函数中文版

    - `free()`: 释放已分配的内存,防止内存泄漏。 3. **错误处理和诊断函数**: - `errno` 和 `perror()`: 错误代码和错误消息打印,帮助调试程序。 - `assert()`: 断言函数,用于检查程序逻辑错误。 4. **字符串...

    Linux 常用C函数(中文版)

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

    Linux系统下C语言gets函数出现警告问题的解决方法

    最近在Linux下编译C语言,用到gets这个函数,代码如下: #include #include #include void main(){ char s[100]; // 存放输入的字符串 int i, j, n; printf(输入字符串:); gets(s); n=strlen(s); for(i=0,j=n-1...

    linux常用C函数(中文版)

    《Linux常用C函数详解》是一本详实的指南,涵盖了在Linux环境下开发程序时常用的C语言函数。本书按章节分类,分别介绍了字符测试、字符串转换、内存控制、日期时间、内存及字符串操作、数学函数、用户组管理、数据...

    linux常用C函数大全

    这篇文档“Linux常用C函数大全”涵盖了在Linux环境下进行C程序开发时可能会遇到的大部分常用函数,旨在提供一个清晰、全面的参考资源。下面,我们将详细讨论这些函数的主要功能和用法。 1. **标准输入输出库函数**...

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

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

Global site tag (gtag.js) - Google Analytics