OSDev.org

The Place to Start for Operating System Developers
It is currently Wed Apr 24, 2024 11:14 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 2 posts ] 
Author Message
 Post subject: Usermode C++ classes vtable problem: Function never returns
PostPosted: Sun Jan 12, 2020 7:59 am 
Offline
Member
Member

Joined: Tue Oct 29, 2013 1:13 pm
Posts: 207
Hi,

I am writing my own stdc/stdc++ libraries as an exercise. I have support for usermode and I have been running binary format code with no problems.

The problem arises when I started adding more template classes in my stdc++ library. I am expanding the std:vector to support a hierarchy with a vector base class and a numbert of specialization templates for different primitive types, e.g. double, float, int, ... etc.

Code:
    template<typename T>
    class basic_vector {
    protected:
        T *t;
        size_t vec_alloc;
        size_t vec_capacity;
        size_t vec_size;

    public:
        typedef std::iterator<bidirectional_iterator_tag, T> iterator;
        typedef std::iterator<bidirectional_iterator_tag, const T> const_iterator;
        typedef size_t size_type;

        basic_vector();
        basic_vector(size_type n);
        virtual void resize(size_type n);
        virtual void resize(size_type n, const T &val);
        virtual iterator begin() noexcept;
        virtual const_iterator begin() const noexcept;
        virtual iterator end() noexcept;
        virtual const_iterator end() const noexcept;
        virtual T &back();
        virtual T &front();
        virtual bool empty();
        virtual void clear();
        virtual T &operator[](size_type index);
        virtual const T &operator[](size_type index) const;
        virtual void push_back(const T &val);
        virtual void push_back(T &&val);
        virtual size_t size() const noexcept;
        virtual size_t capacity() const noexcept;
        virtual void assign(iterator first, iterator last);
        virtual void assign(std::string::const_iterator first, std::string::const_iterator last);
        virtual void assign(size_type n, const T &val);
        virtual void swap(basic_vector &x);
        virtual ~basic_vector();
    };

    template<typename T>
    class vector: public basic_vector<T> {
            public:
                typedef std::iterator<bidirectional_iterator_tag, T> iterator;
                typedef std::iterator<bidirectional_iterator_tag, const T> const_iterator;
                typedef size_t size_type;

                vector();
                vector(size_type n);
                void resize(size_type n);
                void resize(size_type n, const T &val);
                void clear();
                ~vector();
    };

    template<>
    class vector <float>: public basic_vector<float> {
            public:
            typedef std::iterator<bidirectional_iterator_tag, float> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const float> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 
    };

    template<>
    class vector <int>: public basic_vector<int> {
        public:
            typedef std::iterator<bidirectional_iterator_tag, int> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const int> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 
    };

    template<>
    class vector <int *>: public basic_vector<int *> {
            public:
            typedef std::iterator<bidirectional_iterator_tag, int *> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const int *> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 
    };

    template<>
    class vector <double>: public basic_vector<double> {
            public:
            typedef std::iterator<bidirectional_iterator_tag, double> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const double> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 
    };
    template<>
    class vector <char>: public basic_vector<char> {
            public:
            typedef std::iterator<bidirectional_iterator_tag, char> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const char> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 

    };
    template<>
    class vector <unsigned char>: public basic_vector<unsigned char> {
            public:
            typedef std::iterator<bidirectional_iterator_tag, unsigned char> iterator;
            typedef std::iterator<bidirectional_iterator_tag, const unsigned char> const_iterator;
            typedef size_t size_type;
            vector();
            vector(size_type n);
            ~vector(); 
    };




The problem appears at random where in some random places in the code while running inside some function execution is transferred to address 0x0 and the function never returns causing a page fault.

For example I use a local variable object inside a function vector <float> f; when the specialization class template is defined the problem occurs, when I comment out the specialization template the code works. The confusing thing is that with the specialization template enabled as I add some printfs the code runs well and as soon as I comment them out the problem appears?

I am assuming that I might have some corruption in the vtables as the number of classes gets larger.

My questions are:
1. Where exactly is the vtable stored? in which section?
2. How can I make sure to enlarge the space for it ?
3. Is there anything needs to be done in the linker file?

Any ideas what it could be and how to solve it?

Thanks,
Karim.


Top
 Profile  
 
 Post subject: Re: Usermode C++ classes vtable problem: Function never retu
PostPosted: Sun Jan 12, 2020 1:52 pm 
Offline
Member
Member

Joined: Tue Oct 29, 2013 1:13 pm
Posts: 207
Hi,

I did some investigation. Notice the constructor is inline and I could not get it to link except by defining it like that; generates multiple definition linker error otherwise.

I added a printf in the constructor, compiled it, and ran objdump on it and here what I got:

Code:
000000000023b780 <_ZN6tantan13maskSequencesEPhS0_iPKPKdddddddPKh>:
        t = (T *) malloc(n * sizeof(T));
  23b780:       48 b8 60 08 23 00 00    movabs $0x230860,%rax
  23b787:       00 00 00
                   const uchar *maskTable) {
  23b78a:       41 57                   push   %r15
    basic_vector<T>::basic_vector(size_type n) {
  23b78c:       49 bf f8 a2 25 00 00    movabs $0x25a2f8,%r15
  23b793:       00 00 00
  23b796:       41 56                   push   %r14
  23b798:       49 89 ce                mov    %rcx,%r14
  23b79b:       41 55                   push   %r13
  23b79d:       4d 89 c5                mov    %r8,%r13
  23b7a0:       41 54                   push   %r12
  std::vector<float> p(seqEnd - seqBeg);
  23b7a2:       49 89 f4                mov    %rsi,%r12
                   const uchar *maskTable) {
  23b7a5:       55                      push   %rbp
  std::vector<float> p(seqEnd - seqBeg);
  23b7a6:       49 29 fc                sub    %rdi,%r12
                   const uchar *maskTable) {
  23b7a9:       48 89 fd                mov    %rdi,%rbp
  23b7ac:       53                      push   %rbx
        t = (T *) malloc(n * sizeof(T));
  23b7ad:       4a 8d 3c a5 00 00 00    lea    0x0(,%r12,4),%rdi
  23b7b4:       00
  23b7b5:       48 89 f3                mov    %rsi,%rbx
  23b7b8:       48 83 ec 78             sub    $0x78,%rsp
  23b7bc:       89 54 24 14             mov    %edx,0x14(%rsp)
    basic_vector<T>::basic_vector(size_type n) {
  23b7c0:       4c 89 7c 24 40          mov    %r15,0x40(%rsp)
  23b7c5:       c5 fb 11 44 24 18       vmovsd %xmm0,0x18(%rsp)
  23b7cb:       c5 fb 11 4c 24 20       vmovsd %xmm1,0x20(%rsp)
  23b7d1:       c5 fb 11 54 24 28       vmovsd %xmm2,0x28(%rsp)
  23b7d7:       c5 fb 11 5c 24 30       vmovsd %xmm3,0x30(%rsp)
  23b7dd:       c5 fb 11 64 24 38       vmovsd %xmm4,0x38(%rsp)
  23b7e3:       c5 fb 11 6c 24 08       vmovsd %xmm5,0x8(%rsp)
        t = (T *) malloc(n * sizeof(T));
  23b7e9:       ff d0                   callq  *%rax
        vec_alloc = n;
  23b7eb:       4c 89 64 24 50          mov    %r12,0x50(%rsp)
        printf ("inline vector<float>::vector(size_type n):basic_vector<float>(%d)\n",n);
  23b7f0:       4c 89 e6                mov    %r12,%rsi
  23b7f3:       48 bf 10 7e 25 00 00    movabs $0x257e10,%rdi
  23b7fa:       00 00 00
23b7fd:       48 ba f0 a7 22 00 00    movabs $0x22a7f0,%rdx
  23b804:       00 00 00
        t = (T *) malloc(n * sizeof(T));
  23b807:       48 89 44 24 48          mov    %rax,0x48(%rsp)
    inline vector<float>::vector(size_type n):basic_vector<float>(n){
  23b80c:       48 b8 b8 a3 25 00 00    movabs $0x25a3b8,%rax
  23b813:       00 00 00
  23b816:       48 89 44 24 40          mov    %rax,0x40(%rsp)
        printf ("inline vector<float>::vector(size_type n):basic_vector<float>(%d)\n",n);
  23b81b:       31 c0                   xor    %eax,%eax
        vec_capacity = n;
  23b81d:       4c 89 64 24 58          mov    %r12,0x58(%rsp)
        vec_size = 0;
  23b822:       48 c7 44 24 60 00 00    movq   $0x0,0x60(%rsp)
  23b829:       00 00
        printf ("inline vector<float>::vector(size_type n):basic_vector<float>(%d)\n",n);
  23b82b:       ff d2                   callq  *%rdx
  float *probabilities = BEG(p);




When I remove the printf, I do not see the rest of the constructor which shows that it does not get inlined!

Code:
000000000023b780 <_ZN6tantan13maskSequencesEPhS0_iPKPKdddddddPKh>:
        t = (T *) malloc(n * sizeof(T));
  23b780:       48 b8 60 08 23 00 00    movabs $0x230860,%rax
  23b787:       00 00 00
                   const uchar *maskTable) {
  23b78a:       41 56                   push   %r14
  23b78c:       49 89 ce                mov    %rcx,%r14
  23b78f:       41 55                   push   %r13
  23b791:       41 89 d5                mov    %edx,%r13d
  23b794:       41 54                   push   %r12
  23b796:       55                      push   %rbp
  23b797:       48 89 f5                mov    %rsi,%rbp
  23b79a:       53                      push   %rbx
  23b79b:       48 89 fb                mov    %rdi,%rbx
  std::vector<float> p(seqEnd - seqBeg);
  23b79e:       48 89 f7                mov    %rsi,%rdi
  23b7a1:       48 29 df                sub    %rbx,%rdi
  23b7a4:       48 c1 e7 02             shl    $0x2,%rdi
                   const uchar *maskTable) {
  23b7a8:       48 83 ec 30             sub    $0x30,%rsp
  23b7ac:       c5 fb 11 44 24 28       vmovsd %xmm0,0x28(%rsp)
  23b7b2:       c5 fb 11 4c 24 20       vmovsd %xmm1,0x20(%rsp)
  23b7b8:       c5 fb 11 54 24 18       vmovsd %xmm2,0x18(%rsp)
  23b7be:       c5 fb 11 5c 24 10       vmovsd %xmm3,0x10(%rsp)
  23b7c4:       c5 fb 11 64 24 08       vmovsd %xmm4,0x8(%rsp)
  23b7ca:       ff d0                   callq  *%rax
  getProbabilities(seqBeg, seqEnd, maxRepeatOffset,
  23b7cc:       c5 fb 10 64 24 08       vmovsd 0x8(%rsp),%xmm4
  23b7d2:       c5 fb 10 5c 24 10       vmovsd 0x10(%rsp),%xmm3
  23b7d8:       45 31 c0                xor    %r8d,%r8d
  23b7db:       49 89 c4                mov    %rax,%r12
  23b7de:       c5 fb 10 54 24 18       vmovsd 0x18(%rsp),%xmm2
  23b7e4:       4c 89 f1                mov    %r14,%rcx
  23b7e7:       44 89 ea                mov    %r13d,%edx


The C++ core for the above objdump is:

Code:
void maskSequences(uchar *seqBeg,
                   uchar *seqEnd,
                   int maxRepeatOffset,
                   const const_double_ptr *likelihoodRatioMatrix,
                   double repeatProb,
                   double repeatEndProb,
                   double repeatOffsetProbDecay,
                   double firstGapProb,
                   double otherGapProb,
                   double minMaskProb,
                   const uchar *maskTable) {

  std::vector<float> p(seqEnd - seqBeg);
  float *probabilities = BEG(p);
  getProbabilities(seqBeg, seqEnd, maxRepeatOffset,
                   likelihoodRatioMatrix, repeatProb, repeatEndProb,
                   repeatOffsetProbDecay, firstGapProb, otherGapProb,
                   probabilities);
  maskProbableLetters(seqBeg, seqEnd, probabilities, minMaskProb, maskTable);
}


I guess that the compiler does not inline and invoke empty inline constructors even if they delegate the base class constructor.

How can I force it to do so?

The only way to get it done is through removing the constructor delegation and calling the base class constructor from within the derived class constructor.

Thanks,
Karim.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 2 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Bing [Bot], Google [Bot] and 117 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group