web-dev-qa-db-ja.com

Valgrindメッセージ:アドレスXXXは、r-xマップファイル<fielpath>セグメントにあります

自己定義構造に関連するmallocと空きヒープメモリのCを学習しています。

私が出会った問題

以下のコードでは、常に_segment fault_を取得しています。分析にvalgrindを使用すると、次のように示されます:_==12999== Address 0x108b4b is in a r-x mapped file <folder_path> segment ==12999==_

フル出力:

_Name : Amy 
Date of Birth: 1989 9 21
Name : echo 
Date of Birth: 1989 9 21
Name : echo 
Date of Birth: 1989 9 21
Name : echo Address 0x5580be70e270
Date of Birth: 1989 9 21
Their address : 0x5580be70e260 0x5580be70e264 0x5580be70e268
Name : echo Address 0x5580be70e270
Date of Birth: 1989 9 21
Their address : 0x5580be70e260 0x5580be70e264 0x5580be70e268
free p->name 
Segmentation fault (core dumped)

_

私が行った分析

valgrindを使用して、結果の場所を見つけようとします。_valgrind --tool=memcheck --leak-check=full ./person2_出力は次のように表示されます。

_Their address : 0x522d040 0x522d044 0x522d048
Name : echo Address 0x522d050
Date of Birth: 1989 9 21
Their address : 0x522d040 0x522d044 0x522d048
free p->name 
==12999== Invalid free() / delete / delete[] / realloc()
==12999==    at 0x4C30D3B: free (in /usr/lib/valgrind/vgpreload_memcheck-AMD64-linux.so)
==12999==    by 0x108894: Person_destruct (person2.c:33)
==12999==    by 0x108A2F: main (person2.c:74)
==12999==  Address 0x108b4b is in a r-x mapped file /folder/path segment
==12999== 
freed p->name 
free p 
freed p 
==12999== 
==12999== HEAP SUMMARY:
==12999==     in use at exit: 4 bytes in 1 blocks
==12999==   total heap usage: 3 allocs, 3 frees, 1,052 bytes allocated
==12999== 
==12999== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12999==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-AMD64-linux.so)
==12999==    by 0x108817: Person_construct (person2.c:16)
==12999==    by 0x1089CC: main (person2.c:64)
==12999== 
==12999== LEAK SUMMARY:
==12999==    definitely lost: 4 bytes in 1 blocks
==12999==    indirectly lost: 0 bytes in 0 blocks
==12999==      possibly lost: 0 bytes in 0 blocks
==12999==    still reachable: 0 bytes in 0 blocks
==12999==         suppressed: 0 bytes in 0 blocks
==12999== 
==12999== For counts of detected and suppressed errors, rerun with: -v
==12999== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)

_

私が理解しているのは、_*p3_が_p1_(Person_address_print()によって証明された)とまったく同じメモリピースを指しているため、_p1_を明示的に破棄するだけで、同じヒープメモリ。)また、割り当てられた文字列が以前の長さ(3)内にあることを確認するために_p3->name = "ada";_を許可するか、Person_destruct(p1)を呼び出す前に明示的に_p3 == NULL_を設定しました。同じセグメント障害エラーが発生します:(

コード

これがコードです。コードは基本的に次のことを行います。自己定義構造Person b。 (mainで)Personのオブジェクトを作成し、それらを破棄して、関連する属性を出力します。

_//  person.h
#ifndef PERSON_H
#define PERSON_H
typedef struct
{
    int year;
    int month;
    int date;
    char * name; // name is a ponter b/c name length is unknown
} Person;
Person * Person_construct(int y, int m, int d, char * n);
void Person_destruct(Person *p);
void Person_print(Person * p);
#endif
_
_#include "person.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
Person *Person_construct(int y, int m, int d, char *n)
{
    Person *p = NULL;
    p = malloc(sizeof (Person));
    if (p == NULL) // malloc failed
    {
        return NULL;
    }
    p->year= y;
    p->month = m;
    p->date = d;
    p->name = malloc(sizeof(char) * (strlen(n) + 1));
    // + 1 for the neding char '\0'
    if ((p->name) == NULL)// malloc failed, just return
    {
        free(p); 
        return NULL;
    }
    strcpy(p->name, n);
    return p;
}

void Person_destruct(Person *p)
{
    // p->name must be freed befoer p is freed
    if (p->name != NULL)
    {
        printf("free p->name \n");
        free(p->name);
        printf("freed p->name \n");
    }

    if (p != NULL)
    {
        printf("free p \n");
        free(p);
        printf("freed p \n");
    }
}

void Person_print(Person *p)
{
    printf("Name : %s \n", p->name);
    printf("Date of Birth: %d %d %d\n", 
        p->year, p->month, p->date);
}


void Person_address_print(Person *p)
{
    printf("Name : %s Address %p\n", p->name, &(p->name));
    printf("Date of Birth: %d %d %d\n", 
        p->year, p->month, p->date);
    printf("Their address : %p %p %p\n", 
        &(p->year), &(p->month), &(p->date));
}

int main(int argc, char ** argv)
{
    Person * p1 = Person_construct(1989,9, 21, "Amy");
    Person_print(p1);

    Person * p3 = p1;
    p3->name = "echo";
    Person_print(p3);
    Person_print(p1); // p1's name should have changed to "echo".
    Person_address_print(p1);
    Person_address_print(p3);


    Person_destruct(p1);
    // p3 is pointing to the same memory of p1, should not destruct(p3)

    return EXIT_SUCCESS;

}

_

私が走っている環境

gcc(Ubuntu 7.4.0-1ubuntu1〜18.04.1)7.4.0

valgrind-3.13.0

手がかりをどうもありがとう!

1
Jacqueline P.

@kaylumの回答に刺激を受けました。 Cの文字列リテラルの概念を忘れた場合、_p3->name = "echo"_を実行した場合、_p3->name_が文字列リテラルとヒープメモリのmallocである以前に指定されたchar配列を手動で指すようにします、 失うだろう。これがfree(p->name)のときに失敗する理由です。

ありがとう@kaylum!

2
Jacqueline P.