2016-12-06 22 views
-1

私は次の関数(いくつかのアルゴリズムは、おそらく間違っているが、それは問題の技術的な側面だ)との複雑なコードがあります:%オペレータがある過負荷演算子の使用後のコピー(セグメンテーションフォールトを)失敗し

template<int L> 
string toStringBase(const StaticUnsigned<L>& x, int base) { //between {2,...,16} 
    assert(2 <= base && base <= 16); 
    StaticUnsigned<L> t, q, _base, _base_to_n; 
    _base = (uint64_t)base; 
    t = x; 
    q = t; 
    string str = ""; 
    _base_to_n = 1LL; 
    char digits[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; 
    while(t > StaticUnsigned<L>(0ULL)) { 
     q = t % _base; //The problem is here! 
     std::cout << "Partial conversion = " << str << std::endl; 
     str += digits[q.mem[0]]; 
     t = t/_base; //right shift 
    } 
    return str; 
} 

を次のようにオーバーロードされた:

template<int L> 
template<int M> 
inline StaticUnsigned<MaxInt<L, M>::value> StaticUnsigned<L>::operator %(
    const StaticUnsigned<M>& _m) const 
{ 
    StaticUnsigned<MaxInt<L, M>::value> rval, x, y; 
    x = *this; 
    y = _m; 
    if (y > x) { 
     return x; 
    } else { 
     rval = x/y; 
     rval = x - rval * y; 
     return rval; 
    } 
} 

そして

template<int L> 
inline StaticUnsigned<L>::StaticUnsigned(const StaticUnsigned<L>& _m) 
{ 
    set_ui_const(this->mem, _m.mem, L, L); 
} 
を次のように私はコピーコンストラクタを実装した。この特定のケースでは

...何が起こるのですか(gdbから)...私は基本的に関数toStringBaseを呼び出し、関連する関数が呼び出されます。q = t % baseに到達すると、演算子%は適切にコードされています。その場合、elseステートメントが正しく呼び出されます(具体的には、rval変数への代入は問題ありません。コンテンツが正しく計算されています)。しかし、私は変数rvalのコピーが実際に返されると仮定します。ただし、この変数は、関連するステートメントのqに割り当てられていません。 Valgrindのは

0000000000000000 000000000000000a 
==5613== Invalid read of size 8 
==5613== at 0x4012D7: set_ui_const(unsigned long*, unsigned long const*, int, int) (basic.cc:320) 
==5613== by 0x404C9B: StaticUnsigned<75>::operator=(StaticUnsigned<75> const&) (static_unsigned.h:205) 
==5613== by 0x404F1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > toStringBase<75>(StaticUnsigned<75> const&, int) (static_unsigned.h:453) 
==5613== by 0x373635343332312F: ??? 
==5613== by 0x23B3A3937: ??? 
==5613== by 0x7FEFFEFCF: ??? 
==5613== by 0x7FEFFF04F: ??? 
==5613== by 0x373635343332312F: ??? 
==5613== by 0x4645444342413937: ??? 
==5613== Address 0xffffffffffffffd0 is not stack'd, malloc'd or (recently) free'd 
==5613== 
==5613== 
==5613== Process terminating with default action of signal 11 (SIGSEGV) 
==5613== Access not within mapped region at address 0xFFFFFFFFFFFFFFD0 
==5613== at 0x4012D7: set_ui_const(unsigned long*, unsigned long const*, int, int) (basic.cc:320) 
==5613== by 0x404C9B: StaticUnsigned<75>::operator=(StaticUnsigned<75> const&) (static_unsigned.h:205) 
==5613== by 0x404F1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > toStringBase<75>(StaticUnsigned<75> const&, int) (static_unsigned.h:453) 
==5613== by 0x373635343332312F: ??? 
==5613== by 0x23B3A3937: ??? 
==5613== by 0x7FEFFEFCF: ??? 
==5613== by 0x7FEFFF04F: ??? 
==5613== by 0x373635343332312F: ??? 
==5613== by 0x4645444342413937: ??? 
==5613== If you believe this happened as a result of a stack 
==5613== overflow in your program's main thread (unlikely but 
==5613== possible), you can try to increase the size of the 
==5613== main thread stack using the --main-stacksize= flag. 
==5613== The main thread stack size used in this run was 10485760. 
==5613== 

アドレスを返します:0xffffffffffffffd0が返さrvalのコピーのアドレスであると考えられます。しかし、なぜコピーコンストラクタがうまくいくのか理解できません。

template<int L> 
class StaticUnsigned { 
public: 
    StaticUnsigned(); //ok 
    template<int M> 
    StaticUnsigned(const StaticUnsigned<M>& _m); 
    StaticUnsigned(const StaticUnsigned<L>& _m); //ok 
    template<int M = 64> //ok 
    StaticUnsigned<MaxInt<L, M>::value> operator%(
     const StaticUnsigned<M>& _m) const; 
    template<int M = 64> 
    StaticUnsigned<L>& operator=(const StaticUnsigned<M>& _m); //ok 
    StaticUnsigned<L>& operator=(const StaticUnsigned<L>& _m); //ok 
public: 
    uint64_t mem[(L + 63)/64]; 
}; 

そしてset_ui_constは、基本的には、配列のコピーである:(ちょうどスクラッチ、すべてのメソッドが報告されていない)のようなクラスStaticUnsignedに見えるところで

。 問題をデバッグする方法についての手がかりはありますか?私は本当に何を見るべきか分からない。

更新:オペレータ=

template<int L> 
template<int M> 
inline StaticUnsigned<L>& StaticUnsigned<L>::operator =(
    const StaticUnsigned<M>& _m) 
{ 
    if (this != (StaticUnsigned<L>*) (&_m)) { 
     StaticUnsigned<M> tmp = _m; 
     set_ui(this->mem, tmp.mem, L, M); 
    } 
    return *this; 
} 

template<int L> 
inline StaticUnsigned<L>& StaticUnsigned<L>::operator =(
    const StaticUnsigned<L>& _m) 
{ 
    if (this != &_m) { 
     set_ui_const(this->mem, _m.mem, L, L); 
    } 
    return *this; 
} 

アップデート2:

機能set_ui_const

void set_ui_const(uint64_t* y,const uint64_t* x, int ny, int nx) 
{ 
    assert(nx >= 1 && ny >= 1); 

    int Nx, Ny, Nmin, j, n2y; 

    Nx = (nx + 63)/64; 
    Ny = (ny + 63)/64; 
    n2y = (ny - (Ny-1)*64); 
    Nmin = (Nx <= Ny) ? Nx : Ny; 

    for (j = 0; j <= Nmin - 1; j++) 
     y[j] = x[j]; 
    for (j = Nmin; j <= Ny - 1; j++) 
     y[j] = 0ULL; 

    if (n2y != 64) { 
     y[Ny - 1] &= (1ULL << n2y) - 1ULL; 
    } 
} 
+0

'set_ui_const'関数を*表示*できますか?また、 'L'が' 75'(それがそうであるように)で '(75 + 63)/ 64'が' 2.2'の周りにあることを覚えていれば、あなたの配列は '2'要素だけです。 2つの要素だけをコピーしますか?以上? –

+0

基本的に、最初の要素(インデックス '0'を持つ要素)をコピーするのを止めます。しかし、私はサイズが良いと確信しています。 – user8469759

+0

ちなみに、コピーコンストラクタの代わりに代入演算子を表示するべきでしょう。これは、コールスタックに応じて問題につながっているようです。 –

答えて

0

これ:

==5613== Invalid read of size 8 
==5613== at 0x4012D7: set_ui_const(unsigned long*, unsigned long const*, int, int) (basic.cc:320) 
==5613== by 0x404C9B: StaticUnsigned<75>::operator=(StaticUnsigned<75> const&) (static_unsigned.h:205) 
==5613== by 0x404F1D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > toStringBase<75>(StaticUnsigned<75> const&, int) (static_unsigned.h:453) 
==5613== by 0x373635343332312F: ??? 

は、通常で、どこかにスタックバッファオーバーフローがあることを意味します。 「返信」アドレス0x373635343332312F"/1234567"(引用符は含まれていません)がASCIIにあることに注意してください。

この種の問題をデバッグする最善の方法は、-fsanitize=addressフラグを持つGCCとClangの最新バージョンでサポートされているAddress Sanitizerです。

+0

私は静的コンパイルを使用しているので、 'fsanitaze'は動作しません。あなたが強調した線は何を意味しますか? '0x4012D7'はセル' [0] 'の第2引数を読み込みます。セグメンテーション違反がある場所があります。セグメンテーションフォルトが発生したときはわかりますが、理由はわかりません。より正確な分析を行うためにvalgrindを使用することはできませんか?どのように私に提案することができますか? – user8469759

+0

@ user8469759あなたのプログラムのどこにでも '/ 1234567'という文字列がありますか?プログラムの入力には?次に、その文字列がどこで処理されているかを調べ、その文字列に十分なメモリが割り当てられていることを確認する必要があります。 'std :: string'を使うのは、まずは良い場所です。または他の[標準コンテナ](http://en.cppreference.com/w/cpp/container) C++では、最近ポインタやダイナミックメモリの取り扱いを避けることができますが、絶対に必要なとき以外はポインタを使わないようにコードをリファクタリングすることをお勧めします(C関数、多型を呼び出す)。 –

+0

@Employedロシア語、そのような文字列はまったく使用されません。そのような種類の入力は使用されません。ダイナミックな割り当てや割り当て解除は使用されません。 – user8469759

関連する問題