2013-02-19 6 views
9

Tôi đã viết một mã rất đơn giản để lấp đầy hình ảnh 32b32 16bpp với giá trị không đổi (1024). Bộ đệm hình ảnh được lưu trữ theo số std::vector. pitch/stride hình ảnh của tôi (nghĩa là số byte giữa hai dòng liên tiếp) đủ lớn để giữ toàn bộ dòng, nhưng là đặt số lẻ. Đây là mã của tôi:Sụp đổ trong khi điền hình ảnh 16bpp với tối ưu hóa -O3 và độ cao lẻ

#include <vector> 
#include <stdint.h> 

int main() 
{ 
    int width = 32; 
    int height = 32; 
    int pitch = width * 2 + 1; 

    std::vector<uint8_t> image(height * pitch); 
    uint8_t* buffer = &image[0]; 

    for (int y = 0; y < height; y++) 
    { 
    uint16_t* p = reinterpret_cast<uint16_t*>(buffer + y * pitch); 
    for (int x = 0; x < width; x++, p++) 
    { 
     *p = 1024; 
    } 
    } 
} 

Tôi đang sử dụng Linux x86_64 với gcc 4.6.1 (Ubuntu 11.10). Mã chạy tốt với các mức tối ưu hóa -O0, -O1-O2. Valgrind không báo cáo bất kỳ vi phạm truy cập nào. Tuy nhiên, ngay sau khi tôi chuyển sang -O3 hoặc sử dụng tùy chọn -ftree-vectorize để tự động vector, chương trình bị treo:

# g++ -g -O3 ./test.cpp -Wall -pedantic && ./a.out 
Segmentation fault 

# g++ -g -O2 -ftree-vectorize ./test.cpp -Wall -pedantic && ./a.out 
Segmentation fault 

Cả gdb cũng không valgrind cung cấp bất kỳ thông tin hữu ích:

# valgrind ./a.out 
==3840== Memcheck, a memory error detector 
==3840== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. 
==3840== Using Valgrind-3.6.1-Debian and LibVEX; rerun with -h for copyright info 
==3840== Command: ./a.out 
==3840== 
==3840== 
==3840== Process terminating with default action of signal 11 (SIGSEGV) 
==3840== General Protection Fault 
==3840== at 0x4005B3: main (test.cpp:18) 
==3840== 
==3840== HEAP SUMMARY: 
==3840==  in use at exit: 2,080 bytes in 1 blocks 
==3840== total heap usage: 1 allocs, 0 frees, 2,080 bytes allocated 
==3840== 
==3840== LEAK SUMMARY: 
==3840== definitely lost: 2,080 bytes in 1 blocks 
==3840== indirectly lost: 0 bytes in 0 blocks 
==3840==  possibly lost: 0 bytes in 0 blocks 
==3840== still reachable: 0 bytes in 0 blocks 
==3840==   suppressed: 0 bytes in 0 blocks 
==3840== Rerun with --leak-check=full to see details of leaked memory 
==3840== 
==3840== For counts of detected and suppressed errors, rerun with: -v 
==3840== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4) 
Segmentation fault 

Vụ tai nạn không xảy ra khi tôi chuyển sang các tệp nhị phân 32 bit với cờ gcc -m32. Nó không xảy ra hoặc nếu tôi sử dụng một sân chẵn (ví dụ: pitch = width * 2 + 2). Bất cứ ai có thể giúp tôi để phát hiện các (chắc chắn là ngu ngốc) lỗi tôi thực hiện trong mã của tôi? Rất cám ơn trước!


UPDATE: Theo đề nghị của Jonathan, tôi vừa báo cáo vấn đề này để các nhà phát triển GCC: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56392

+0

Tính toán độ cao của bạn trông không bình thường. Bạn có ý định đặt nó thành một giá trị lẻ n (tốt, một số lẻ của các phần tử uint16_t) không? Nó phổ biến hơn để xem nó được làm tròn đến bội số của 4 hoặc 8. – simonc

+0

Có, nó được cố tình đặt thành một số lẻ. Vụ tai nạn không xảy ra với thậm chí cả sân ... và tôi không thể tìm ra lý do tại sao bởi bản thân mình :) – Tisys

+1

So sánh mã lắp ráp đã tạo. Ngoài ra, bạn có thể muốn thử nghiệm với các tùy chọn riêng lẻ '-O3' bật để xem cái nào là thủ phạm (Xem http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Optimize-Options. html # Tối ưu hóa-Tùy chọn cho một danh sách các tùy chọn). –

Trả lời

4

Câu hỏi của tôi đã trả lời bởi Richard Blener trên gcc Bugzilla:

"Bạn đang dereferencing một con trỏ đến uint16_t mà không đủ liên kết cho loại đó. Các tiêu chuẩn C cấm này, dẫn đến hành vi không xác định."

Theo tôi, một cảnh báo tuy nhiên nên được tạo về hành vi không xác định này. Cũng xin lưu ý rằng giải thích này cũng đã được đưa ra bởi @jmetcalfe trong các ý kiến ​​cho bài đăng này.

+3

'reinterpret_cast' là cách của bạn nói với trình biên dịch để đóng cửa và chỉ cần di chuyển con trỏ. Có rất nhiều kịch bản hầu như không thể phát hiện liên quan đến reinterpret_cast rằng cố gắng để viết cảnh báo cho họ là vô ích. – thiton

+1

@ Tisys, không nhầm lẫn không xác định và không xác định, chúng rất khác nhau –

+0

@ Jonathan, cảm ơn nhận xét, đã sửa :) – Tisys