Android — Получение ошибки сегментации SIGSEGV в memcpy после mmap

Я написал простую встроенную функцию Android, которая получает имя файла и еще несколько аргументов и читает файл, используя mmapping (mmap) его памяти.

Поскольку это mmap, мне не нужно вызывать read (), поэтому я просто memcpy () с адреса, возвращенного из mmap ().

Но где-то я получаю SIGSEGV, вероятно, потому что я пытаюсь получить доступ к памяти, которую я не разрешил. Но я не понимаю почему, я уже попросил отобразить всю память файла!

Я прилагаю свой код и полученную ошибку:

РЕДАКТИРОВАТЬ

Я исправил неопределенный цикл, но все еще получал SIGSEGV после того, как были прочитаны 25001984 байта.
Функция работает с этими аргументами:
jn_bytes = 100 000 000
jbuffer_size = 8192
jshared = 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);
}

и журнал ошибок:

    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)

1

Решение

Здесь есть большая проблема:

    addr+=jbuffer_size;

Ты натыкаешься addr от sizeof(int) * jbuffer_size байт, тогда как вы просто хотите увеличить его на jbuffer_size байт.

Мое предположение sizeof(int) 4 в вашей системе, следовательно, вы терпите крах примерно на 25% пути в вашем цикле, потому что вы увеличиваете addr в 4 раза больше на каждой итерации.

3

Другие решения

Этот цикл никогда не заканчивается, потому что ret_val всегда равняется buffer

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;
}

memcpy всегда возвращает свой первый аргумент, поэтому ret_val никогда не меняется

1

while цикл бесконечен:

while(ret_val == buffer || read_length<jbuffer_size) {
ret_val = memcpy(buffer, addr,jbuffer_size);
addr+=jbuffer_size;
read_length -= jbuffer_size;
}

как memcpy() всегда возвращает буфер десинтации ret_val == buffer всегда будет true (и поэтому бесполезен как часть условия завершения). Это означает, что addr увеличивается на jbuffer_size байт на каждой итерации цикла и передается memcpy(), получая доступ к недействительной памяти.

1

Состояние в while(ret_val == buffer || read_length<jbuffer_size) неправильно. ret_val == buffer всегда будет правдой, и если read_length<jbuffer_size истинно, когда цикл достигнут, он всегда останется верным, потому что read_length только когда-либо уменьшается (ну, пока он не опустится до INT_MIN).

1
По вопросам рекламы [email protected]