4

タイトルが説明的でない場合は申し訳ありません。問題を一言で表すのは難しいです。私はmalloc'ingによって利用可能なメモリの量を見つけようとしており、それが機能した場合はそのセグメントに書き込みます。特定のシステム (x86_64 上のすべての Linux) では、2049 番目の mib に書き込むときにセグメンテーション違反が発生します。コードは次のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>

int main (int argc, char **argv) {
    void *addr;
    int megasize = 2100
    /// allocate the memory via mmap same result
    //addr = mmap ((void *) 0, (size_t) megasize << 20, PROT_READ | PROT_WRITE,
    //                                                      MAP_PRIVATE | MAP_ANONYMOUS, (int) -1, (off_t) 0);
    addr = malloc(megasize << 20);
    if (addr == MAP_FAILED) {
            fprintf (stderr, "alloc of %d megabytes failed %s\n", megasize,
            strerror (errno));
            exit (1);
    };
    printf ("got %d megabytes at %p\n", megasize, addr);
    {
            int i;
            char *p = addr;
            printf("touching the %d Mb memory:\n", megasize);
            for (i = 0; i < megasize; i++) {
                    p[i << 20] = 0;
                    putchar('.');
                    if (i%64==63) // commenting out this line i see that it really is the 2049th mb
                            printf(" #%d\n", i);
                    fflush(stdout);
            };
            putchar('\n');
    };
    /// free the memory
    munmap (addr, (size_t) megasize << 20);
    return 0;
} 

一部のシステムではセグメンテーション違反が確実に発生しますが、他のシステムでは問題なく動作します。失敗したシステムのログを読むと、それが oom killer ではないことがわかります。malloc が失敗する原因となるメガサイズの値を選択できますが、それらはより大きくなります。segfault は、サイズが 2gib より大きく、malloc がこれらのシステムで -1 を返す制限よりも小さい場合に確実に発生します。

malloc によって監視されていない制限があり、それが何であるかを理解できません。RLIMIT_AS や RLIMIT_DATA のように関連があると思われる getrlimit を介していくつかの制限を読み出そうとしましたが、それらははるかに大きかったです。

これは私のvalgrindlogの関連部分です

==29126== Warning: set address range perms: large range [0x39436000, 0xbc836000) (defined)
==29126== Invalid write of size 1
==29126==    at 0x400AAD: main (in /home/max/source/scratch/memorytest)
==29126==  Address 0xffffffffb9436000 is not stack'd, malloc'd or (recently) free'd

誰が問題が何であるかについて手がかりを教えてもらえますか?

4

2 に答える 2

8

ここでは 4 バイト幅であるint iため、を介してカウントするとオーバーフローが発生します。int

p[i << 20] = ...

変化する

int i;

することが

size_t i;

size_tメモリをアドレス指定する場合に優先されるタイプです。

于 2012-12-12T14:15:51.017 に答える
5

32ビットintでは値2049mbを格納できません。符号付き整数のオーバーフローを介して未定義の動作を呼び出しており、たまたま負の数を取得しています。ほとんどの32ビットマシンでは、誤ってラップアラウンドして目的のアドレスを提供するポインタに追加された場合。64ビットマシンでは、メモリブロックの先頭から約2047 mbのアドレスが得られます(または64ビットメモリスペースの先頭にラップアラウンドされます)。

適切なタイプを使用してください。ここでiは、タイプが必要size_tです。

于 2012-12-12T14:39:03.777 に答える