หน่วยความจำรั่วและข้อผิดพลาด valgrind ใน for loop ขนาดเล็กนี้หรือไม่

ฉันมีปัญหากับส่วนเล็กๆ ของโค้ดที่สร้างข้อผิดพลาดใน valgrind เมื่อฉันแสดงความคิดเห็นโค้ดและรัน valgrind ฉันไม่ได้รับหน่วยความจำรั่วหรือข้อผิดพลาดใด ๆ ดังนั้นการวนซ้ำนี้ควรเป็นสาเหตุ:

///Print the top users
    const char* str;
    for (int i = 0; i < count; i++) {
        if (FinalArray[i].Score == -1) {
            break;
        }

        int id = UserGetID(user);
        char* name = UserGetName(user);
        int finalID = UserGetID(FinalArray[i].user);
        char* finalName = UserGetName(FinalArray[i].user);

        assert(finalName!= NULL && name !=NULL);
        str = mtmSuggestFriends(id, name, finalID, finalName);

        if (str == NULL) {
            return MAIN_ALLOCATION_FAILED;
        }

//      fprintf(fileOutput, str);
    }

หลังจากการวนซ้ำนี้ ฉันก็แค่ส่งคืนแจงนับที่ระบุความสำเร็จ

นี่คือข้อผิดพลาดใน Valgrind:

==8779== Use of uninitialised value of size 8
==8779==    at 0x4037C2: UserGetName (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FAC: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== Use of uninitialised value of size 8
==8779==    at 0x4037A0: UserGetID (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FC8: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== Invalid read of size 1
==8779==    at 0x403F1A: mtmSuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FEE: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==  Address 0x9848B4458BB44589 is not stack'd, malloc'd or (recently) free'd
==8779== 
==8779== Process terminating with default action of signal 11 (SIGSEGV)
==8779==  General Protection Fault
==8779==    at 0x403F1A: mtmSuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x401FEE: SuggestFriends (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x402E6D: executeUserCommand (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779==    by 0x40281B: main (in /u1/023/mtm/ex2/RUN/mtm_isocial)
==8779== 
==8779== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 4 from 1)
==8779== malloc/free: in use at exit: 1,250 bytes in 93 blocks.
==8779== malloc/free: 455 allocs, 362 frees, 10,081 bytes allocated.
==8779== For counts of detected errors, rerun with: -v
==8779== searching for pointers to 93 not-freed blocks.
==8779== checked 122,512 bytes.
==8779== 
==8779== LEAK SUMMARY:
==8779==    definitely lost: 0 bytes in 0 blocks.
==8779==      possibly lost: 0 bytes in 0 blocks.
==8779==    still reachable: 1,250 bytes in 93 blocks.
==8779==         suppressed: 0 bytes in 0 blocks.
==8779== Reachable blocks (those to which a pointer was found) are not shown.
==8779== To see them, rerun with: --show-reachable=yes

ฟังก์ชัน ToStringUser ส่งคืน malloc ของ const char*.. ดังนั้นฉันไม่ควรกังวลเกี่ยวกับการปล่อยมันใช่ไหม

มีความคิดใด ๆ ว่าทำไมสิ่งนี้ถึงเกิดขึ้น?

ฉันพยายามปล่อย str ด้วยโค้ดนี้ใน for แต่ฉันได้รับข้อผิดพลาดเดิมและหน่วยความจำรั่วในปริมาณเท่าเดิม:

free((char*) str); OR free((void*) str);

นี่คือโครงสร้างของผู้ใช้และ getID และ getName:

struct User_t {
    char *Name;
    int ID;
    int Birth;
};
int UserGetID(User user) {
    return user->ID;
}
char* UserGetName(User user) {
    return user->Name;
}

ก่อนที่ลูปฉันจะเริ่มต้นผู้ใช้ใหม่ด้วยสิ่งนี้:

User user = FindUserPointer(setUser, id);

ฟังก์ชั่นที่ใช้คือ:

static User FindUserPointer(Set users, int ID) {
        assert(users!=NULL);
    User tmpUser = UserCreate("temp", ID, 99);
    if (tmpUser == NULL) {
        return NULL;
    }
    SET_FOREACH(User,Itrator1,users) {
        if (UserCompare(tmpUser, Itrator1) == 0) {
            UserFree(tmpUser);
            return Itrator1;
        }
    }
    UserFree(tmpUser);
    return NULL;
}

person Omar    schedule 04.05.2012    source แหล่งที่มา
comment
ทำไมคุณไม่ต้องกังวลกับการปลดปล่อยมันล่ะ?   -  person msam    schedule 04.05.2012
comment
คุณควรกังวลเกี่ยวกับการเพิ่มหน่วยความจำเสมอ   -  person Philip    schedule 04.05.2012
comment
user ใน for loop คืออะไร และโปรแกรมมี segfaults ในฟังก์ชัน mtmSuggestFriends ดังนั้นจึงอาจมีประโยชน์หากจะดู   -  person huon    schedule 04.05.2012
comment
@msam แม้ว่าฉันจะปลดปล่อยมันด้วยการแคสต์ str to void* หรือ char* ฉันก็ยังคงได้รับข้อผิดพลาดเหล่านี้และบล็อก 93 ของหน่วยความจำรั่ว   -  person Omar    schedule 04.05.2012
comment
@dbaupp ฉันสร้างผู้ใช้และรับตัวชี้ไปยังผู้ใช้นั้นเมื่อเริ่มต้นฟังก์ชันนี้ (ก่อนลูป): User user = FindUserPointer(setUser, id); เกี่ยวกับ mtmSuggestFriends นั้น มันอยู่ในไฟล์อ็อบเจ็กต์ และฉันไม่มีรหัส แม้ว่ามันไม่ควรเป็นสาเหตุของปัญหา เพราะเพื่อนของฉันไม่มีปัญหาในการใช้งาน   -  person Omar    schedule 04.05.2012
comment
@Philip ฉันจะปล่อย const.. ได้อย่างไร? แม้ว่าฉันจะปล่อย str ด้วยการร่าย ฉันยังได้รับข้อผิดพลาดและหน่วยความจำรั่ว อัปเดตคำถามแล้ว   -  person Omar    schedule 04.05.2012
comment
@Omar โปรแกรมขัดข้อง การรั่วไหลของคุณเป็นอีกปัญหาหนึ่ง   -  person IanNorton    schedule 04.05.2012
comment
@Omar: โดยการเรียก free() ;) โปรดทราบว่า free() จะไม่เปลี่ยนค่าของอาร์กิวเมนต์ถึงแม้ว่ามันจะไม่สำคัญก็ตาม   -  person Philip    schedule 04.05.2012
comment
@Philip ฉันได้รับข้อผิดพลาดนี้เมื่อปล่อย str โดยไม่มีการส่ง: ผ่านอาร์กิวเมนต์ 1 ของ 'free' ละทิ้งคุณสมบัติ 'const' จากประเภทเป้าหมายตัวชี้   -  person Omar    schedule 04.05.2012
comment
@Omar โปรแกรมขัดข้อง (นั่นคือสิ่งที่ Invalid read of size 1 + SIGSEGV หมายถึง) คุณควรแก้ไขก่อนที่คุณจะกังวลมากเกินไปเกี่ยวกับ freeing หน่วยความจำ   -  person huon    schedule 04.05.2012
comment
@โอมาร์: คุณพูดถูก ฉันค้นหามันแล้ว และวิธีแก้ปัญหาเชิงสำนวนคืออย่าใช้ const พอยน์เตอร์เพื่อเก็บผลลัพธ์ของ malloc() มันไม่สมเหตุสมผลเลย เนื่องจากคุณจะต้องเปลี่ยน (เช่น free()) ตัวชี้ในภายหลัง   -  person Philip    schedule 04.05.2012
comment
@ Philip ปัญหาคืออย่างอื่น ฉันกำลังออกจากขอบเขตอาเรย์ เมื่อฉันแก้ไขแล้ว ฉันไม่มีข้อผิดพลาดหรือหน่วยความจำรั่ว ฉันไม่ต้องปล่อย const .. มันเป็นอิสระโดยอัตโนมัติฉันเดา :) ขอบคุณสำหรับความช่วยเหลือสำหรับคุณและคนอื่นๆ ทั้งหมด!   -  person Omar    schedule 04.05.2012


คำตอบ (3)


Valgrind ไม่ได้บ่นเกี่ยวกับการรั่วไหล แต่เป็นการบ่นว่าคุณกำลังอ่านหน่วยความจำที่ไม่ได้เตรียมใช้งานและยกเลิกการอ้างอิงพอยน์เตอร์ที่ไม่ถูกต้อง (ตัวชี้ deref ที่ไม่ถูกต้องกำลังทำให้โปรแกรมหยุดทำงาน - อย่างน้อยก็ภายใต้ Valgrind)

เราจำเป็นต้องดู UserGetID() และ UserGetName() เพื่อให้มีความหวังในการระบุจุดบกพร่องในสิ่งเหล่านั้น (แต่นั่นอาจยังไม่เพียงพอ)

จากความคิดเห็นของคุณที่ mtmSuggestFriends เป็นไฟล์อ็อบเจ็กต์ที่คุณไม่มีแหล่งที่มา ฉันเดาว่า UsetGetID() และ/หรือ UserGetName() กำลังส่งพอยน์เตอร์ที่ไม่ถูกต้องไปที่ mtmSuggestFriends

person Michael Burr    schedule 04.05.2012
comment
คำถามอัปเดตด้วยรหัส mtmSuggestFriends เป็นฟังก์ชันในไฟล์อ็อบเจ็กต์ มัน mallocs และส่งคืน const char* มันไม่ใช่สาเหตุของการรั่วไหลอย่างที่เพื่อนของฉันหลายคนใช้มันและมีการรั่วไหล 0 ครั้งเมื่อใช้งาน - person Omar; 04.05.2012
comment
ฉันอัปเดต for loop ด้วย asserts (ดูโค้ดด้านบน) และมันยังคงใช้งานได้ - person Omar; 04.05.2012
comment
ตอนนี้เรารู้มากขึ้นแล้ว แต่ไม่รู้ว่าข้อมูลที่ส่งไปยัง FindUserPointer() มีลักษณะอย่างไร หรือ SET_FOREACH() คืออะไร แต่จากคำอธิบายของคุณเกี่ยวกับ mtmSuggestFriends ปัญหาอาจเป็นเพราะฮีปเสียหาย บางที UserCreate() มีข้อบกพร่อง (อาจจะไม่จัดสรรหน่วยความจำเพียงพอที่จะรวมจุดสิ้นสุดที่เป็นโมฆะในสตริง Name?) - person Michael Burr; 04.05.2012
comment
@Omar: ก้าวผ่านลูปในดีบักเกอร์ ฉันจะเดิมพันในบางจุด name กลายเป็น non-NULL แต่ชี้ไปที่หน่วยความจำไร้สาระ / ไม่ถูกต้อง นั่นจะยังคงผ่าน assert() แต่จะไม่ทำให้ mtmSuggestFriends() มีความสุข - person Michael Burr; 04.05.2012
comment
ฉันทำอย่างนั้น และพบว่าการทดสอบที่เราต้องการมีผู้ใช้มากกว่าที่ฉันมีจริงๆ ดังนั้นฉันจึงต้องตรวจสอบจำนวนผู้ใช้ที่ได้รับเป็นจำนวนสูงสุดที่ฉันสามารถพิมพ์ได้ (และไม่มากกว่านั้น) ดังนั้นฉันจึงออกจาก FinalArray ขอบเขต ฉันเพิ่ม if(..) เล็กน้อย และตอนนี้ฉันไม่มีหน่วยความจำรั่วหรือข้อผิดพลาด ขอบคุณสำหรับความช่วยเหลือ Michael - person Omar; 04.05.2012

ขั้นแรก คุณกำลังส่งผ่านตัวชี้ที่ยังไม่ได้กำหนด user จากนั้นฟังก์ชัน SuggestFriends() ของคุณที่ถูกเรียกจาก UserGetID() กำลังใช้ตัวชี้ขยะนี้ซึ่งเต็มไปด้วยการสุ่มเป็นตัวชี้จริง ซึ่งนำไปสู่การอ่านที่ไม่ถูกต้อง (SEGV)

คุณอาจพบว่าการตั้งค่า "คำเตือนเป็นข้อผิดพลาด" (-Werr บน gcc) อาจแสดงให้คุณเห็นว่าคุณกำลังทำอะไรที่คาดเดาไม่ได้

person IanNorton    schedule 04.05.2012
comment
ฉันอัพเดตโค้ดโดยที่ผู้ใช้กำหนด ฉันดีบั๊กโค้ดด้วย eclipse และผู้ใช้ไม่เป็น NULL เมื่อพบข้อผิดพลาดนี้ - person Omar; 04.05.2012
comment
แน่นอนว่ามันไม่ใช่ NULL มันเป็นค่าที่ไม่ใช่ตัวชี้ที่ถูกต้อง อาจมาจากที่ valgrind บ่นเกี่ยวกับการใช้ตัวแปรที่ไม่ได้เตรียมใช้งาน คุณควรเริ่มต้นพอยน์เตอร์เป็น NULL เสมอ - person IanNorton; 04.05.2012
comment
ฉันลองกับสิ่งนี้: User user = NULL; ผู้ใช้ = FindUserPointer (setUser, id); นี่คือสิ่งที่คุณหมายถึงใช่ไหม? ฉันยังคงได้รับข้อผิดพลาดเดียวกัน ฉันยังพยายามส่งคืน COPY ของผู้ใช้ใน FindUserPointer แต่ก็ยังมีรอยเปื้อนอยู่ - person Omar; 04.05.2012

struct User_t {
char *Name;
int ID;
int Birth;
};
int UserGetID(User user) {
    return user->ID;
}

...และ User ถูกกำหนดไว้ที่ไหน?

person msam    schedule 04.05.2012