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已经是无效指针。
分享到:
相关推荐
而`freeifaddrs`则用于释放由`getifaddrs`分配的内存资源。 在Android中,由于NDK(Native Development Kit)环境与标准的Linux环境存在差异,`getifaddrs`和`freeifaddrs`可能不在默认的链接库中。因此,当你尝试...
在Linux下,使用到的C语言函数中文手册,全都有实例,如果你是大神,完全不需要,如果你对英文的手册感到头疼,而且是初学者,对很多用到的函数不太熟悉,这个文档对你有很大的帮助。 这里包含了所有的linux下C编程...
linux下面实现kbhit函数
本文将深入探讨Linux下的内存池实现,包括其原理、优势以及如何在C或C++中进行实践。 内存池的基本原理是预先一次性申请一大块连续内存,并将其分割成多个固定大小的小块,这些小块被称为内存块或者对象。当程序...
vmalloc函数用于分配虚拟内存,vfree函数用于释放虚拟内存。vmalloc函数的用法与kmalloc函数相似,但是vmalloc函数可以分配更大的内存块。 Linux C中的内存分配函数非常重要,包括malloc, kmalloc, zalloc等等。每...
特别是在动态内存分配场景下,如果不妥善处理,很容易出现内存泄露的问题。内存泄露不仅会消耗系统资源,还可能导致应用程序性能下降甚至崩溃。因此,掌握如何有效地检测和定位内存泄露问题显得尤为重要。本文将详细...
本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考,涵盖了在Linux环境下编程时经常会遇到的一些关键函数。这些函数是C语言标准库的一部分,同时也是Linux系统调用的基础。下面,我们将深入探讨一些重要...
本资料集主要探讨了Linux环境下C语言的内存控制函数,这些函数在编写高效、安全的C程序时至关重要。 1. `malloc()` 函数:这是最常用的动态内存分配函数,用于向系统申请指定大小的内存空间。其原型为`void* malloc...
linux下实现getch函数
本文将深入探讨WinCE环境下的内存释放机制,以及如何有效地进行内存管理和优化。 1. WinCE内存管理基础 WinCE内存管理系统采用了一个与Windows NT相似的模型,包括堆、栈和全局数据区等部分。堆是动态分配内存的...
在易语言内存释放源码中,通常会包含使用这些API函数来实现的示例代码,例如编写一个工具,扫描并显示系统中所有进程的内存使用情况,或者检测特定程序的内存泄漏。这种工具对于调试和优化程序的内存性能非常有用。...
在Linux环境下进行C语言编程,理解并掌握常用的C库函数是至关重要的。这份"LinuxC常用函数手册"为你提供了一份详尽的参考资料,涵盖了Linux C编程中的基础到高级的函数用法。以下是一些关键的知识点: 1. **标准...
linux开发手册 函数API接口查询 系统调用以及相关库函数的使用说明
- `free()`: 释放已分配的内存,防止内存泄漏。 3. **错误处理和诊断函数**: - `errno` 和 `perror()`: 错误代码和错误消息打印,帮助调试程序。 - `assert()`: 断言函数,用于检查程序逻辑错误。 4. **字符串...
本资源“Linux常用C函数(中文版)”提供了一份详细的C函数参考指南,以方便开发者查找和理解Linux环境下C语言编程时常用的功能函数。这份资料采用HTML格式,便于在网页浏览器中查看和搜索,利用浏览器的"Ctrl+F...
最近在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程序开发时可能会遇到的大部分常用函数,旨在提供一个清晰、全面的参考资源。下面,我们将详细讨论这些函数的主要功能和用法。 1. **标准输入输出库函数**...
本资源提供了两个文档,一个是"linux的c函数(Word版).doc",另一个是"Linux_C_fun.pdf",它们都包含了关于Linux环境下常用C语言函数的详细资料。下面我们将深入探讨这些知识点。 1. **标准库函数**: - `stdio.h`...