2017-11-25 7 views
0

이 코드는 IncludeOS github page에서 가져옵니다. 다른 헤더 파일없이 컴파일되도록 약간 수정했습니다. IncludeOS의 find 함수가 너무 장황하기 때문에이를 단순화하고 싶습니다. 그러나 수정 후, 코드는 예상했던 것과 다르게 동작합니다.clang ++ 메모리 sanitizer가 사용 초기화되지 않은 값을보고합니다.

다음은 간단한 설명입니다. 이 코드는 HTTP 헤더를 구문 분석하는 데 사용됩니다. 머리글 필드는 이름 - 값 쌍입니다. vector<pair<string, string>>으로 표시됩니다. find 함수는 헤더의 필드 이름 위치를 찾는 데 사용되며 has_field은 헤더에 특정 필드 이름이 존재하는지 확인하는 데 사용됩니다.

main 함수에는 네 개의 요소가 필드에 추가됩니다. six은 fields에 없습니다. 그러나 has_field은 true를 반환합니다.

gdb으로 오류를 추적하려고했습니다. 그러나 나는 산출물의 바다에서 길을 잃었다. 나는 다소 흥미로운 메시지를 찾았다.

표준 : __ uninitialized_copy < 거짓 > :: __ uninit_copy < __gnu_cxx :: __ normal_iterator < 표준 : : 쌍 < 표준 : __ cxx11 :: 표준 < 문자, 표준 : : char_traits < 문자 > :: 할당 <를 basic_string 숯불 > >, 표준 : __ cxx11 :: < CHAR, 표준 : char_traits <CHAR>, 표준 : 할당 <CHAR> > > CONST의 * STD : 벡터 < 표준 : 쌍 :: __ cxx11 < 성병 basic_string :: basic_string < 문자, 표준 : : char_traits < 문자 <, 표준 : : 할당 < 문자 > >, 표준 : __ cxx11 :: basic_string < 문자, 표준 : : char_traits < 문자 >, 표준 : : 할당 < 문자 > > > , 표준 : : 할당 < 표준 : : 쌍 < 표준 : __ cxx11 :: basic_string < 문자, 표준 : : char_traits < 문자 <, 표준 : : 할당 < 문자 > >, 표준 : __ cxx11 :: basic_string < 문자, 표준 : : char_traits <char>, std :: allocator <char> > > > > >, 표준 : 쌍 < 표준 : __ cxx11 :: basic_string < CHAR, 표준 : char_traits <CHAR>, 표준 : 할당 <CHAR> >, 표준 : __ cxx11 :: < 숯불 basic_string, STD :: char_traits <CHAR>, 표준 : 할당 <CHAR> > > > * (__first = {제 = "하나"초 = "1"} __last =

{= 제 < 오류 판독 변수 : 없다 게으른 문자열 만들기 주소 0x0 및 0이 아닌 길이 >, 초 = ""}, __result = 0x61bf00)

내가 뭐가 잘못 알아 clang 소독제를 사용했다. 메모리 소독제 만 흥미로운 보고서를 보여줍니다.,

clang++ -std=c++17 -O1 -fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer main.cc

/a.out 리포트

초기화되지 않은 값 _ZNSt4pairINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES5_EC2IRA6_KcRA2_S8_Lb1EEEOT_OT0_'` '함수의 스택 프레임에서'ref.tmp '의 할당에 의해 생성 된 실행.

최적화 수준을 -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; 
} 
+1

가 초기화되지 않은 값에 대해 알고하지 않습니다,하지만 당신은 값으로'fields' 벡터를 전달하고, 따라서 'has_field'이 벡터의 다른 사본에 반복자를 비교합니다. –

+0

@BoPersson 네 말이 맞아. 값으로 전달 된 컨테이너에 반복자를 반환하는 것은 매우 잘못입니다. 여기에 관련된 stackoverflow 질문입니다. https://stackoverflow.com/questions/10113572/does-passing-containers-by-value-invalidate-iterators – JohnKoch

답변

1

가양 성일 가능성이 있습니다. 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
  • 내가, 오류가 사라 참조로 fields를 취할 a를 선언하면이 개 기능은

를 호출있다; 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 
+0

가양 성일 가능성이 있습니다. 나는 'valgrind --tool = memcheck --track-origins = yes./a.out'을 다시 사용하여이를 확인합니다. 아무것도 나타나지 않습니다. Bo-Persson은 내 프로그램에 문제가 있음을 발견했습니다. 나는 값으로 벡터를 전달하고 있었고, 반복자를 돌려 주었다. 이것은 매우 나쁘다. – JohnKoch