本文介绍了获取分段错误SIGSEGV中的memcpy MMAP后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了得到一个文件名和一些参数和mmapping(MMAP),它的内存读取文件一个简单的Andr​​oid原生功能。

由于它的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 ^做过,堆叠的a​​rgs = [帧= {级=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后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-22 14:22