2016-12-06 2 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의 사본의 주소로되어있다. 하지만 왜 복사 생성자가 잘되어야하는지 이해할 수 없습니다. 클래스 StaticUnsigned처럼 보이는 방법 (모든 방법을보고 그냥 스크래치)으로

:

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는 기본적으로 배열 복사합니다. 문제를 디버그 할 수있는 방법에 대한 단서가 있습니까? 나는 무엇을보아야할지 정말로 모른다.

업데이트 : 운영자 =

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' 요소 만 있다는 것을 기억하십시오. 두 가지 요소 만 복사합니까? 이상? –

+0

기본적으로 첫 번째 요소 (색인 '0'을 가진 요소)를 복사하는 것이 중지됩니다. 그러나 나는 크기가 괜찮다고 확신합니다. – user8469759

+0

그런데 call-stack에 따라 문제를 일으키는 것으로 보이는 복사 생성자 대신 할당 연산자를 보여 주어야합니다. –

답변

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]'에서 두 번째 인수를 읽습니다. 분할 오류가있는 곳이 있습니다. 세분화 오류가 발생하는 시점을 알지만 그 이유는 알 수 없습니다. valgrind를 사용하여 더 정확한 분석을 수행 할 수 있습니까? 어떻게 나에게 제안 해 줄 수 있니? – user8469759

+0

@ user8469759 프로그램의 어느 곳에서나'/ 1234567' 문자열이 있습니까? 프로그램 입력에? 그런 다음 해당 문자열이 처리되는 위치를보고 해당 문자열에 할당 된 메모리가 충분한 지 확인해야합니다. 'std :: string'을 사용하는 것은 좋은 출발점입니다. 또는 다른 [표준 컨테이너] (http://en.cppreference.com/w/cpp/container). C++에서는 요즘 대부분 포인터와 동적 메모리 처리를 피할 수 있지만 절대적으로 필요한 경우 (C 함수, 다형성 호출)를 제외하고 포인터를 사용하지 않도록 코드를 리팩토링하려고하는 것이 좋습니다. –

+0

@Employed 러시아어, 그런 문자열은 전혀 사용되지 않습니다. 이러한 종류의 입력은 사용되지 않습니다. dynanic 할당 또는 할당 취소는 사용되지 않습니다. – user8469759