首先看一段代码:
typedef WORD unsigned short;
JNIEXPORT jobject XXX_getString(JNIEnv* env, jobject thiz, jint file,jobject head,jobject word,jint index)
{
jobject jstr = NULL;
int i = 0,j,len;
WORD *buf;
int adr = (*env)->GetIntField(env,word,wd_ExplainAddress);
len = getWordStartAddress(file,index + 1,(*env)->GetIntField(env,head,dh_CodeAddressTable)) - adr;
buf = (WORD*)malloc(len + 2);
if(buf == NULL){
return NULL;
}
lseek(file,adr,SEEK_SET);
read(file,buf,len);
buf[len / 2 + 1] = 0;
while(buf[i]){
if((buf[i] >= 0xF800) &&(buf[i] <= 0xF8FF) || (buf[i] >= 0xF700) &&(buf[i] <= 0xF70D)){
j = i;
while(buf[j]){
buf[j] = buf[j + 1];
j++;
}
continue;
}
i++;
}
buf[i] = 0;
jstr = (*env)->NewString(env,buf,i);
free(buf);
return jstr;
}
就是上面的一段代码,其中有一行有问题,导致了出现“@@@ ABORTING: INVALID HEAP ADDRESS IN dlfree”错误
通过错误提示,说明是内存出错了,而且是在free的时候出错的,即上面第33行。但是free怎么会出错呢,除非前面malloc的内存出错了,要么free是错误的地址,或者malloc的内存被访问越界了,粗看一下,buf的地址没变过,因此地址不会错,难道是越界?那究竟是怎么越界的呢?
buf 指针为WORD型,分配了(len+2)个字节,说明最小有2个字节,然后buf[len/2+1]=0,将分配的最后一个WORD置0,所以20行和23行的while语句也是不会越界的。那到底是哪里呢?你可能说len小于0的话就不行,因为这个len是计算出来的,所以逻辑上已经排除了。好,len也不会小于0,while循环也不会出界,那怎么还会出错呢?
仔细看一下,如果len是奇数呢,比如3,buf = malloc(3+2),buf有5个字节,第19行,buf[3/2+1] = buf[2] = 0,因为buf是WORD型的,每个元素2个字节,buf[2]就是buf开始后的第5、6个字节,因为分配的buf只有5个字节,现在要访问第6个字节,所以越界了。
测试中发现,第9行得到的len一直都是偶数,并不存在奇数的情况,可还是一样的错误,因此这个属于内存对齐的问题了。关于内存对齐,网上资料比较多,这里贴出一个网址以供参考:
内存对齐的规则以及作用
不好意思,上面加删除线的一段话其实是错误的,不知道有多少人看了这篇博客,误导了大家,实在对不起!这里其实不是对齐的问题,就是内存越界了,主要祸根就是第11行,这里本来是要申请一块连续的WORD(每个元素2个字节)型空间的,结果申请的是BYTE(每个元素1个字节)型空间,因为malloc是按字节数来分配的,所以尽管增加了2个字节的长度,在后面肯定是会内存出界的。上面的buf[2]应该是buf开始后的第4、5个字节,因此还没出界。现在用偶数代替,比如len=4,buf=malloc(4+2),buf有6个字节,第19行,buf[4/2+1]=buf[3]=0,因为buf是WORD型,buf[3]就是buf开始后的第6、7个字节,因为分配的buf只有6个字节,现在要访问第7个字节,所以越界了。由此可见,指针的使用必须要严格谨慎,必须要有扎实的C语言基础,还要了解程序数据在内存中的布局情况,否则一不留神轻则程序出错,重则系统崩溃!