问题描述
我写了得到一个文件名和一些参数和mmapping(MMAP),它的内存读取文件一个简单的Android原生功能。
由于它的MMAP,我并不真的需要调用读取(),所以我刚才的memcpy()从MMAP地址()返回。
但是,在某处,我得到一个SIGSEGV可能是因为我想访问我不允许的内存。但我不明白为什么,我已经问过的所有文件的存储器映射!
我附上我的code,我得到了错误:
修改
我固定unterminating循环,但仍然得到SIGSEGV 25001984字节被读取后。该函数可以使用这些参数:jn_bytes =亿jbuffer_size = 8192jshared = jpopulate = jadvice = 0
无效Java_com_def_benchmark_Benchmark_testMma $ P $垫(JNIEnv的* ENV,jobject javaThis,
的jstring jfile_name,无符号整型jn_bytes,无符号整型jbuffer_size,jboolean jshared,jboolean jpopulate,jint jadvice){
为const char * FILE_NAME = ENV-> GetStringUTFChars(jfile_name,0);
/ * ***开始计*** * /
INT FD =打开(FILE_NAME,O_RDONLY);
//获取文件的大小
为size_t长度= lseek的(FD,0L,SEEK_END);
使用lseek(FD,0L,SEEK_SET);
长度=长度GT; jn_bytes jn_bytes:长度?
// 2人MMAP:因为Linux 2.6.23 MAP_POPULATE只支持民营映射
INT标志= 0;
如果(jshared)标志| = MAP_SHARED;其他标志| = MAP_PRIVATE;
如果(jpopulate)标志| = MAP_POPULATE;
// INT标志= MAP_PRIVATE;
INT *地址= reinter pret_cast<为int *>(MMAP(NULL,长度,PROT_READ,旗帜,FD,0));
如果(地址== MAP_FAILED){
__android_log_write(ANDROID_LOG_ERROR,NDK_FOO_TAG,字符串错误(错误));
返回;
}
INT * initaddr =地址;
如果(jadvice大于0)
的madvise(地址,长度,jadvice == 1(MADV_SEQUENTIAL | MADV_WILLNEED):( MADV_DONTNEED?));
关闭(FD);
字符缓冲区[jbuffer_size]
无效* RET_VAL =缓冲区;
INT read_length =长度;
而(RET_VAL ==缓冲|| read_length< jbuffer_size){
/ *****抵达SIGSEGV SOMWHERE在这里的WHILE ************ /
RET_VAL =的memcpy(缓冲区,地址,jbuffer_size);
地址+ = jbuffer_size;
read_length - = jbuffer_size;
}
在munmap(initaddr,长度);
/ *停止计数* /
ENV-> ReleaseStringUTFChars(jfile_name,FILE_NAME);
}
和错误日志:
15736 ^做起来难
(GDB)
15737信息信号SIGSEGV
&功放;信息信号SIGSEGV \ N
〜信号停止\ t打印\ tPass到程序\ tDescription \ N
〜SIGSEGV是\ tYes \ tYes \ t \ tSegmentation故障\ N
15737 ^做
(GDB)
15738-Stack的列表参数0 0 0
15738 ^做过,堆叠的args = [帧= {级=0,ARGS = []}]
(GDB)
15739-Stack的名单,当地人0
15739 ^做,当地人= []
(GDB)
有一个很大的问题就在这里:
地址+ = jbuffer_size;
您正在颠簸地址
按的sizeof(int)的* jbuffer_size
字节,而你只是想在加一 jbuffer_size
字节。
我的猜测是的sizeof(int)的
4在系统上,因此你在崩溃周围的方式25%通过你的循环,因为你递增地址
以4倍的太多每次迭代的一个因素。
I wrote a simple Android native function that get a filename and some more arguments and read the file by mmapping (mmap) it's memory.
Because it's mmap, I don't really need to call "read()" so I just memcpy() from the address returned from the mmap().
But, somewhere I'm getting a SIGSEGV probably because I'm trying to access a memory which I not permitted. But I don't understand why, I already asked all file's memory to be mapped!
I'm attaching my code and the error I got:
EDIT
I fixed the unterminating loop, but still getting SIGSEGV after 25001984 bytes have been read.The function works on those arguments:jn_bytes = 100,000,000jbuffer_size = 8192jshared=jpopulate=jadvice=0
void Java_com_def_benchmark_Benchmark_testMmapRead(JNIEnv* env, jobject javaThis,
jstring jfile_name, unsigned int jn_bytes, unsigned int jbuffer_size, jboolean jshared, jboolean jpopulate, jint jadvice) {
const char *file_name = env->GetStringUTFChars(jfile_name, 0);
/* *** start count *** */
int fd = open(file_name, O_RDONLY);
//get the size of the file
size_t length = lseek(fd, 0L, SEEK_END);
lseek(fd, 0L, SEEK_SET);
length = length>jn_bytes?jn_bytes:length;
// man 2 mmap: MAP_POPULATE is only supported for private mappings since Linux 2.6.23
int flags = 0;
if (jshared) flags |= MAP_SHARED; else flags |= MAP_PRIVATE;
if(jpopulate) flags |= MAP_POPULATE;
//int flags = MAP_PRIVATE;
int * addr = reinterpret_cast<int *>(mmap(NULL, length , PROT_READ, flags , fd, 0));
if (addr == MAP_FAILED) {
__android_log_write(ANDROID_LOG_ERROR, "NDK_FOO_TAG", strerror(errno));
return;
}
int * initaddr = addr;
if(jadvice > 0)
madvise(addr,length,jadvice==1?(MADV_SEQUENTIAL|MADV_WILLNEED):(MADV_DONTNEED));
close(fd);
char buffer[jbuffer_size];
void *ret_val = buffer;
int read_length = length;
while(ret_val == buffer || read_length<jbuffer_size) {
/*****GETTING SIGSEGV SOMWHERE HERE IN THE WHILE************/
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}
munmap(initaddr,length);
/* stop count */
env->ReleaseStringUTFChars(jfile_name, file_name);
}
and the error log:
15736^done
(gdb)
15737 info signal SIGSEGV
&"info signal SIGSEGV\n"
~"Signal Stop\tPrint\tPass to program\tDescription\n"
~"SIGSEGV Yes\tYes\tYes\t\tSegmentation fault\n"
15737^done
(gdb)
15738-stack-list-arguments 0 0 0
15738^done,stack-args=[frame={level="0",args=[]}]
(gdb)
15739-stack-list-locals 0
15739^done,locals=[]
(gdb)
There is a big problem here:
addr+=jbuffer_size;
You're bumping addr
by sizeof(int) * jbuffer_size
bytes whereas you just want to increment it by jbuffer_size
bytes.
My guess is sizeof(int)
is 4 on your system, hence you crash at around 25% of the way through your loop, because you're incrementing addr
by a factor of 4x too much on each iteration.
这篇关于获取分段错误SIGSEGV中的memcpy MMAP后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!