“偶尔”细分错误

时间:2019-05-13 12:50:01

标签: c++ mingw endianness

问题与GRIB解析器有关(链接到GRIB文件https://github.com/Gifciak/GRIB), 当我执行代码时(尽管代码块或通过控制台在Linux上-with dts as ( select date'2018-01-01' + level - 1 dt from dual connect by level <= 7 ) select to_char ( dt, 'Day' ) day_name, ( dt - trunc ( dt + 1, 'iw' ) ) day_number from dts order by day_number; DAY_NAME DAY_NUMBER Sunday -1 Monday 0 Tuesday 1 Wednesday 2 Thursday 3 Friday 4 Saturday 5 ),我遇到了错误,即分段错误,但并非总是如此。

例如,当我编译10次时,有8次会出现错误,而2次一切都可以正常工作,这将为我提供控制台输出和信息。

根据我的研究,问题g++ main.cpp -pedantic所在,因为它可能正在尝试一个不再存在的复制迭代器。

有人可以解释为什么会发生吗? 为什么它不总是崩溃或成功?

std::copy

这是预期的结果,因为我已经从控制台复制了它

size: 4538
sec0: 8
sec1: 28
sec2: 178
sec3: 4320
end flag: 4
sum: 4538

### Section IS ###
magicFlag: 1196575042
size: 1191186874
edition: 1

### Section PDS ###
size: 28
tableVersion: 2
indentificatorOfCenter: 7
numProcessID: 81
gridIndentification: 37
flagForGDSorBMS: 128
indParamAndUnit: 33
indTypeOfLevelOrLayer: 100
levelOrLayer: 850
year: 15
month: 3
day: 10
hour: 0
minute: 0
forecastTimeUnit: 1
p1: 0
p2: 0
indTimeRange: 10
averageOrAccumulate: 0
missing: 0
century: 21
subcenterId: 0
decimalScale: 1

1 个答案:

答案 0 :(得分:5)

首先,使用g++ main.cpp -pedantic并不是很有用,因为您尚未启用任何警告。将-Wall -Wextra添加到编译器标志中,同时也添加-g,以便您对其进行调试。

使用-fsanitize=undefined进行编译会显示由于在需要有效指针的地方使用空指针而导致的运行时错误:

/usr/include/c++/8/bits/stl_algobase.h:368:23: runtime error: null pointer passed as argument 2, which is declared to never be null
Segmentation fault (core dumped)

这意味着您的程序存在错误。

使用-D_GLIBCXX_DEBUG进行编译会向std::vector添加其他检查,这会告诉您问题所在:

/usr/include/c++/8/debug/safe_iterator.h:374:
Error: attempt to advance a past-the-end iterator 4 steps, which falls 
outside its valid range.

Objects involved in the operation:
    iterator @ 0x0x7fffb09ceb90 {
      type = __gnu_debug::_Safe_iterator<__gnu_cxx::__normal_iterator<unsigned char const*, std::__cxx1998::vector<unsigned char, std::allocator<unsigned char> > >, std::__debug::vector<unsigned char, std::allocator<unsigned char> > > (constant iterator);
      state = past-the-end;
      references sequence with type 'std::__debug::vector<unsigned char, std::allocator<unsigned char> >' @ 0x0x7fffb09cf050
    }
Aborted (core dumped)

您应该在调试器下运行程序,以查看此无效的迭代器增量发生在何处。在GDB中运行该程序,然后使用其up命令向上移动堆栈,显示错误来自loadData中的错误:

    constexpr char MAGIC_START[4] = { 'G', 'R', 'I', 'B' };
    constexpr char MAGIC_END[4] = { '7', '7', '7', '7' };

    auto start = std::search(rawdata.cbegin(),
        rawdata.cend(),
        std::begin(MAGIC_START),
        std::end(MAGIC_START));

    auto end = std::search(rawdata.cbegin(),
        rawdata.cend(),
        std::begin(MAGIC_END),
        std::end(MAGIC_END));

    ByteVec data(start, end + sizeof(MAGIC_END));
                        ^^^^^^^^^^^^^^^^^^^^^^^

请考虑当rawdata不包含MAGIC_START字符,但确实包含MAGIC_END字符时会发生什么。 startend会形成有效的迭代器范围吗?

请考虑当rawdata不包含MAGIC_END字符时会发生什么。 end + sizeof(MAGIC_END)有效吗?

您不应假定对std::search的两个调用均能正常工作。您应该通过测试start == rawdata.end()end == rawdata.end()来添加一些错误检查。如果其中任何一个为真,则说明出现了问题(rawdata字符串中可能输入错误)。

您还应该学习如何使用调试器,并了解编译器提供的用于检测错误的其他工具(例如,应使用GCC的-fsanitize=undefined-D_GLIBCXX_DEBUG选项来帮助确认是否存在错误) ,并且应该使用GDB查找这些错误的发生位置。

相关问题