2017-11-25 14 views
0

このコードはIncludeOS github pageから取られています。他のヘッダファイルなしでコンパイルするように少し修正しました。 IncludeOSからのfindの機能は少し冗長すぎるので、私はそれを単純化したいと思います。しかし、変更後、コードは私が期待したものとは異なる動作をします。clang ++メモリサニタイザは、初期化されていない値の使用を報告します

ここで簡単な説明をします。このコードは、HTTPヘッダーの解析に使用されます。ヘッダーフィールドは名前と値のペアです。それはvector<pair<string, string>>と表されます。 find関数は、ヘッダー内のフィールド名の場所を検索するために使用され、has_fieldは、特定のフィールド名がヘッダーに存在するかどうかを確認するために使用されます。

mainの機能では、4つの要素がフィールドに追加されます。 sixはfieldsに見つかりません.はtrueを返します。

私はgdbでエラーを追跡しようとしました。しかし、私は出力の海で失われた。私はやや面白いメッセージを見つけました。

のstd :: __ uninitialized_copy <偽> :: __ uninit_copy < __gnu_cxx :: __ normal_iterator <のstd ::ペア<のstd :: __ cxx11 :: <チャーのbasic_string、STD :: char_traits <文字>、STD ::アロケータ< > >をchar型、のstd :: __ cxx11 :: <チャーのbasic_string、STD :: char_traits <文字>、STD ::アロケータ<文字> > >のconst *、のstd ::ベクトル<のstd ::ペア<のstd :: __ cxx11 ::のbasic_string <チャー、STD :: char_traits <チャー<、スタンダード::アロケータ<チャー> >、STD :: __ cxx11 ::のbasic_string <チャー、STD :: char_traits <チャー>、スタンダード::アロケータ<チャー> > > 、STD ::アロケータ<のstd ::ペア<のstd :: __ cxx11 ::のbasic_string <チャー、STD :: char_traits <チャー<、スタンダード::アロケータ<チャー> >、STD :: __ cxx11 ::のbasic_string <チャー、STD: :char_traits <char>、std :: allocator <char> > > > > >、STD ::対<のstd :: __ cxx11 :: <チャーのbasic_string、STD :: char_traits <チャー>、スタンダード::アロケータ<チャー> >、STD :: __ cxx11 ::のbasic_string <チャー、STD :: char_traits <チャー>、スタンダード::アロケータ<チャー> > > * >(__first = {最初= "1"、第二= "1"}、__last =

変数を読み取る{最初= <エラー:できません怠惰な文字列を作成するアドレス0x0、および長さがゼロでない。 >、二= ""}、__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にはsymbolizerバイナリが付属しているため、サニタイザは行番号を出力できます。私はこの最小限の例を使用してエラーを再現するために管理してきました。どちらの場合も

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

関連する問題