2012-03-01 17 views
6

chỉnh sửa: Tôi đã tìm ra với sự trợ giúp của người nhận xét. Để trả lời các câu hỏi đặt ra trong tiêu đề của tôi: Không, nó không phải là ngăn xếp tham nhũng, gdb của nó báo cáo các giá trị sai. Chương trình thực sự hoạt động như mong đợi và có con trỏ bên phải this. Hành vi buggy thực tế khiến tôi đăng câu hỏi này có lẽ hoàn toàn không liên quan đến vấn đề tôi mô tả ở đây.Constructor được gọi với con trỏ "this" sai. Đây có phải là tham nhũng ngăn xếp không?

Cảnh báo đầu tiên. Tôi tin rằng đây là một vấn đề về bộ nhớ tham nhũng, và tôi thường không mong đợi câu trả lời ngoại trừ "kiểm tra mã của bạn kỹ lưỡng", nhưng tôi đã thấy hành vi này bật lên liên tục và hy vọng một số bạn đã hiểu rõ vấn đề và cách tôi có thể tìm thấy nguồn của nó.

Tôi hiện đang triển khai phân tích tĩnh khoảng thời gian theo dõi phạm vi có thể có của các biến trong chương trình C. Các nhà xây dựng bản sao cho khoảng thời gian lớp cơ sở của tôi trông như thế này:

itvt::itvt(const itvt& i) 
    : _i(i.type == INTBV ? new intbv_intervalt(i.i()) : NULL), 
    _f(i.type == FLOAT ? new float_intervalt(i.f()) : NULL), 
    type(i.type), other_bottom(i.other_bottom) 
{ } 

Bây giờ, tôi tìm thấy một lỗi bộ nhớ tham nhũng và quản lý để theo dõi nó vào đoạn mã sau đây:

itvt itvt::get_split(bool le) const 
{ 
    itvt result(*this); 
    [...] 
} 

Sử dụng gdb, tôi thấy rằng cuộc gọi đến hàm tạo dường như không xây dựng đối tượng "kết quả":

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) n 
519 if(is_singleton() || is_bot()) 
(gdb) print result 
$3 = { 
    _i = { 
    _M_ptr = 0x7fff5fbfe100 
    }, 
    _f = { 
    _M_ptr = 0x7fff5fbfed60 
    }, 
    type = 1606410016, 
    other_bottom = 255 
} 
(gdb) print *this 
$4 = { 
    _i = { 
    _M_ptr = 0x1020833a0 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

Nhìn sâu hơn, tôi thấy rằng bên trong trình tạo bản sao, con trỏ "này" trỏ đến đối tượng sai:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) print &result 
$5 = (itvt *) 0x7fff5fbfdee0 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) print this 
$6 = (itvt * const) 0x7fff5fbfdf80 

Kể từ khi "kết quả" được cấp phát trên stack tại địa chỉ 0x7fff5fbfdee0, tôi mong chờ sự "này" con trỏ bên trong constructor sao chép để trỏ đến cùng một địa chỉ. Thay vào đó, nó trỏ tới 0x7fff5fbfdf80.

Có vẻ như hàm tạo bản sao đang khởi tạo một cái gì đó, nhưng không phải là đối tượng "kết quả" trên ngăn xếp mà nó được gọi. Trong thực tế, tôi có thể truy cập vào vị trí bộ nhớ mà các nhà xây dựng khởi tạo hoàn toàn tốt:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) finish 
Run till exit from #0 itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
itvt::get_split (this=0x1016af560, le=false) at itv.cpp:519 
519 if(is_singleton() || is_bot()) 
(gdb) print *((const itvt*) (0x7fff5fbfdf80)) 
$7 = { 
    _i = { 
    _M_ptr = 0x1016b6d10 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

câu hỏi đầu tiên của tôi: Can một thực tế là "này" điểm con trỏ đến đối tượng sai được giải thích như hành vi bình thường? Nó có vẻ như một số vấn đề tham nhũng bộ nhớ lạ, nhưng có lẽ tôi đang thiếu một cái gì đó.

Tôi đang biên dịch bằng cờ g ++ và "-O0 -ggdb" và đã biên dịch lại mọi thứ btw. Dưới đây là g ++ phiên bản của tôi:

[email protected] ai$ g++ --version 
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) 
Copyright (C) 2007 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

câu hỏi thứ hai của tôi: Nếu đó là bộ nhớ tham nhũng, bạn có lời khuyên nào về làm thế nào tôi có thể theo dõi các nguồn. Tôi thường làm theo các vấn đề như vậy với nguyên nhân gốc rễ của họ bằng cách sử dụng gdb, nhưng tôi không biết nơi để xem xét ngay bây giờ.

Đây không phải là lần đầu tiên tôi gặp phải hành vi cụ thể này. Tôi đã nhìn thấy nó xảy ra khi nhìn vào lỗi của người khác. Tôi chưa bao giờ thực sự trực tiếp quản lý để giải quyết nó trực tiếp, nó chỉ dừng lại xảy ra hoặc ít nhất là một vấn đề có thể nhìn thấy sau khi một số thay đổi mã khác. Điều này khiến tôi tin rằng có lẽ nó chỉ là một đồ vật kỳ lạ khi nhìn vào ngăn xếp bằng gdb.

Tôi biết ơn vì bất kỳ lời khuyên hoặc thông tin chi tiết nào bạn có thể cung cấp.

chỉnh sửa: Dưới đây là là đoạn có liên quan của lớp itvt:

class itvt 
{ 
protected: 
    typedef std::auto_ptr<intbv_intervalt> iptrt; 
    typedef std::auto_ptr<float_intervalt> fptrt; 
    iptrt _i; 
    fptrt _f; 
public: 
    typedef enum {INTBV, FLOAT, OTHER} itv_typet; 
    itv_typet type; 

    bool other_bottom; 

    //copy constr 
    itvt(const itvt& i); 

    inline intbv_intervalt& i() { return *_i; } 
    inline float_intervalt& f() { return *_f; } 
    inline const intbv_intervalt& i() const { return *_i; } 
    inline const float_intervalt& f() const { return *_f; } 

    itvt get_split(bool le) const; 

    [...] 
}; 
+0

Cảm ơn thông tin, điều đó thật thú vị đối với tôi trong một ngữ cảnh khác. Không, lớp itvt hoàn toàn nhàm chán/không ảo. Không có ảo hay thừa kế nào liên quan đến itvt hoặc các thành viên của nó. – leo

+1

Chỉ là một câu hỏi: là phiên bản 'gdb' của bạn được cập nhật. Tôi đã nhìn thấy trường hợp sử dụng một phiên bản cũ của 'gdb' với một phiên bản mới hơn của trình biên dịch gây' gdb' để hiển thị những điều sai trái. (Một ưu tiên, điều này chỉ nên là một vấn đề khi thay đổi phiên bản chính: khi g ++ 4.0.0 đầu tiên xuất hiện, nó mất gdb một thời gian để bắt kịp. Nhưng bạn không bao giờ biết.) –

+2

Điểm thứ hai là khi bạn làm 's 'để bước vào một hàm, một số trình gỡ lỗi (tôi không chắc chắn về gdb --- tôi đã thấy điều này với VS, tuy nhiên) không đi đủ vào chức năng cho khung ngăn xếp cục bộ được thiết lập. Điều này dẫn đến tất cả các giá trị không đúng (khi được trình gỡ rối xem). –

Trả lời

4

Thứ hai câu hỏi: sử dụng valgrind, nó thực sự những gì bạn cần ở đây. Nó theo dõi tất cả các phân bổ/miễn phí, và cho bạn biết nếu bạn cố gắng và sử dụng bộ nhớ giải phóng, cũng như rất nhiều thứ khác. Nó sẽ cho bạn thấy một sự hư hỏng về bộ nhớ.

2

Tôi đã tìm ra với sự giúp đỡ của người nhận xét: Có vẻ như gdb không nói sự thật, (có thể do phiên bản gdb cũ). Chương trình thực sự hoạt động như mong đợi.

Hành vi lỗi thực tế đã nhắc tôi xem xét vấn đề hoàn toàn không liên quan đến khởi tạo đối tượng.