Этот код взят из Включите страницу github. Я немного изменил его, чтобы он компилировался без других заголовочных файлов. find
Функция от IncludeOS слишком многословна, поэтому я хочу упростить ее. Но после модификации код ведет себя не так, как я ожидал.
Вот краткое объяснение. Этот код используется для анализа заголовков HTTP. Поля заголовка — это пары имя-значение. Это представлено как vector<pair<string, string>>
, find
функция используется, чтобы найти расположение имени поля в заголовке, и has_field
используется, чтобы проверить, существует ли определенное имя поля в заголовке.
В main
функция, четыре элемента добавляются к полям. six
не должен быть найден в полях. Но has_field
возвращает истину.
Я пытался отследить ошибку с gdb
, Но я потерялся в море выходов. Я нашел несколько интересное сообщение.
станд :: __ uninitialized_copy<ложный>:: __ uninit_copy<__gnu_cxx :: __ normal_iterator<станд :: пара<станд :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> >, std :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> > > const *, std :: vector<станд :: пара<станд :: __ cxx11 :: basic_string<char, std :: char_traits<голец<, std :: allocator<голец> >, std :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> > >, std :: allocator<станд :: пара<станд :: __ cxx11 :: basic_string<char, std :: char_traits<голец<, std :: allocator<голец> >, std :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> > >>>>, std :: pair<станд :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> >, std :: __ cxx11 :: basic_string<char, std :: char_traits<голец>, std :: allocator<голец> > >*> (__first = {first = «one», second = «1»}, __last =
{первый = <ошибка чтения переменной: невозможно создать ленивую строку с адресом 0x0 и ненулевой длиной.>, second = «»}, __result = 0x61bf00)
я использовал clang
дезинфицирующее средство, чтобы выяснить, что не так. Только очиститель памяти показывает интересные отчеты. Бег,
clang++ -std=c++17 -O1 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer main.cc
/a.out
отчеты,
Неинициализированное значение было создано путем выделения ‘ref.tmp’ в фрейме стека функции ‘_ZNSt4pairINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EC2IRA6_KcRA2_S8_Lb1EEEOT_OT0_’`.
Когда уровень оптимизации установлен на -O3
Однако ничего не появляется.
#include <algorithm>
#include <iostream>
#include <vector>
#include <experimental/string_view>
using Headers = std::vector<std::pair<std::string, std::string>>;
using string_view = std::experimental::string_view;
Headers::const_iterator find(Headers fields, const string_view field) {
if (field.empty()) return fields.cend();
//-----------------------------------
return
std::find_if(fields.cbegin(), fields.cend(), [field](const auto _) {
return std::equal(_.first.cbegin(), _.first.cend(), field.cbegin(), field.cend(),
[](const auto a, const auto b) { return std::tolower(a) == std::tolower(b); });
});
}
bool has_field(Headers fields, const string_view field)
{
return find(fields, field) != fields.cend();
}
int main()
{
Headers fields;
fields.emplace_back("one", "1");
fields.emplace_back("two", "2");
fields.emplace_back("three", "3");
fields.emplace_back("four", "4");
std::string s = "six";
if (has_field(fields, s))
std::cout << s << " is in " << "fields" << std::endl;
return 0;
}
Это скорее всего ложный позитив. llvm поставляется с двоичным символом, который позволяет дезинфицирующему средству выводить номера строк. Мне удалось воспроизвести вашу ошибку на этом минимальном примере:
1 #include <iostream>
2 #include <vector>
3
4 using Headers = std::vector<int>;
5
6 bool a(Headers fields) {
7 return true;
8 }
9
10 bool b(Headers fields)
11 {
12 return a(fields);
13 }
14
15 int main()
16 {
17 Headers fields;
18
19 if (b(fields)) {
20 std::cout << std::endl;
21 }
22
23 return 0;
24 }
В обоих случаях требования трассировки стека std::endl
виновник Чтобы произошла ошибка, должны произойти следующие магические вещи:
std::endl
Если я заявляю a
принять fields
по ссылке ошибка исчезает; то же самое нельзя сказать о b
, Все это приводит меня к мысли, что это бессмысленно и ложно положительно. Для справки, вот вывод дезинфицирующего средства с номерами строк:
Uninitialized bytes in __interceptor_memcmp at offset 192 inside [0x7fff18347610, 256)
==5724==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x7f8f663d94ab in std::ctype<char>::_M_widen_init() const (/lib64/libstdc++.so.6+0xb74ab)
#1 0x7f8f66435d17 in std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&) (/lib64/libstdc++.so.6+0x113d17)
#2 0x4912ff in main test.cpp:20:15
#3 0x7f8f65415889 in __libc_start_main (/lib64/libc.so.6+0x20889)
#4 0x41a9b9 in _start (a.out+0x41a9b9)
Uninitialized value was created by an allocation of 'ref.tmp' in the stack frame of function '_ZNSt6vectorIiSaIiEEC2ERKS1_'
#0 0x491360 in std::vector<int, std::allocator<int> >::vector(std::vector<int, std::allocator<int> > const&) /usr/bin/../lib/gcc/x86_64-redhat-linux/7/../../../../include/c++/7/bits/stl_vector.h:329
SUMMARY: MemorySanitizer: use-of-uninitialized-value (/lib64/libstdc++.so.6+0xb74ab) in std::ctype<char>::_M_widen_init() const
Exiting
Других решений пока нет …