free(): double free detected in tcache 2, composition

I am trying to simulate a simple 2-level paging mechanism, which dynamically creates new entries into the page tables. I am facing extra memory freed errors, when I try to run it with Valgrind and getting the error "free(): double free detected in tcache 2" on running it normally. Can someone help me where I am doing it wrong, I had made proper destructors with conditions, still it is giving such error.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <iostream>

using namespace std;

class page
{

long int page_vaddr;
long int page_paddr;

public:

void set_page_map(long int vaddr, long int paddr)
{
    page_vaddr=vaddr;
    page_paddr=paddr;
}

long int get_page_vaddr()
{
    return page_vaddr;
}

};


class pte
{
long int pte_vaddr;
page *_pte;
int pte_index;

public:

pte()
{
    pte_index=-1;
}

~pte()
{
    cout<<"\npte_index "<<pte_index<<endl;
    if(pte_index>=0)
    delete[] _pte;
}

void add_in_pte(long int vaddr, long int paddr)
{
    pte_index++;
    if(pte_index==0)
    {
        _pte=new page[1];
    }
    if(pte_index>0 && pte_index<512)
    {
        page *pte_new = new page[pte_index+1];
        copy(_pte, _pte + min(pte_index, pte_index+1), pte_new);
        delete[] _pte;
        _pte=pte_new;
    }
    _pte[pte_index].set_page_map(vaddr,paddr);
}
page* access_in_pte(long int vaddr)
{
    int index;
    for(int i=0;i<=pte_index;i++)
    {
        if(_pte[i].get_page_vaddr()==vaddr)
            {index=i;break;}
    }
    return &_pte[index];
}

void set_pte_vaddr(long int vaddr)
{
    pte_vaddr=vaddr;
}

int get_pte_vaddr()
{
    return pte_vaddr;
}
};

class pmd
{
pte *_pmd;
int pmd_index;

public:

pmd()
{
    pmd_index=-1;
}

~pmd()
{
    cout<<"\npmd_index "<<pmd_index<<endl;
    if(pmd_index>=0)
    delete[] _pmd;
}

void add_in_pmd(long int vaddr)
{
    pmd_index++;
    if(pmd_index==0)
    {
        _pmd=new pte[1];
    }
    if(pmd_index>0 && pmd_index<512)
    {
        pte *pmd_new = new pte[pmd_index+1];
        copy(_pmd, _pmd + min(pmd_index, pmd_index+1), pmd_new);
        delete[] _pmd;
        _pmd=pmd_new;
    }
    _pmd[pmd_index].set_pte_vaddr(vaddr);
}
pte* access_in_pmd(long int vaddr)
{
    int index;
    for(int i=0;i<=pmd_index;i++)
    {
        if(_pmd[i].get_pte_vaddr()==vaddr)
            {index=i;break;}
    }
    return &_pmd[index];
}

};

int main()
{

pmd p;
p.add_in_pmd(1);
//p.add_in_pmd(2);  don't get error while doing this
pte *q=p.access_in_pmd(1);
q->add_in_pte(10,20);
//p.add_in_pmd(2);  gets an error here

return 0;

}
Last edited on
Please post
formatted
code so that it is readable!

Use:

[code]
// code goes here
[/code]

Thanks, I had changed it.
One problem is on line 128 return &_pmd[index];

What value will have index when if(_pmd[i].get_pte_vaddr()==vaddr) is false ?

BTW. Why don't you use a std::vector instead of dynamic array ?
I am using another function to maintain this, which will search the complete array and only then execute access_in_pmd()

In the mean time, in this program in main, I am only accessing those which are already stored and can be verified by using search function before accessing.

As I have mentioned in the main, where I am facing the problem. When I execute p.add_in_pmd(2) in the 141 line.

Because, it delete the old record in pmd (which in turn delete inner entries of other class as the result of composition) and create new array, there it is calling an extra delete[], which is the reason of the error. But I am not able to correct this error.

Yes, I am considering using std::vector, but still thought to figure out the problem with this hard-written code.
Last edited on
delete or free of null is fine. if you set to null after release, even if it tries to do it twice, it is harmless.
that said, its better if you trace out the logic and figure out what went wrong.
try initializing all your class pointers to nullptr on construction. Start there.
Last edited on
Another problem I see is that the "Rule of 5 is not followed"
https://en.cppreference.com/w/cpp/language/rule_of_three
With using std::vector the code becomes much easier.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <vector>

using namespace std;

class page
{
  long int page_vaddr = 0L;
  long int page_paddr = 0L;
public:
  page(long int p_vaddr, long int p_paddr): page_vaddr(p_vaddr), page_paddr(p_paddr)
  {}

  void set_page_map(long int vaddr, long int paddr)
  {
    page_vaddr = vaddr;
    page_paddr = paddr;
  }

  long int get_page_vaddr()
  {
    return page_vaddr;
  }
};

class pte
{
  std::vector<page> _pte;
  long int pte_vaddr = 0L;
public:
  pte(long int vaddr): pte_vaddr(vaddr)
  {
    _pte.reserve(512);
  }

  void add_in_pte(long int vaddr, long int paddr)
  {
    if(_pte.size() > 512)
      return;

    _pte.emplace_back(vaddr, paddr);
  }
  page* access_in_pte(long int vaddr)
  {
    for (page& p: _pte)
      if (p.get_page_vaddr() == vaddr)
        return &p;
  
    return nullptr;
  }

  void set_pte_vaddr(long int vaddr)
  {
    pte_vaddr = vaddr;
  }

  int get_pte_vaddr()
  {
    return pte_vaddr;
  }
};

class pmd
{
  std::vector<pte> _pmd;
public:
  pmd() = default;

  void add_in_pmd(long int vaddr)
  {
    _pmd.emplace_back(vaddr);
  }
  pte* access_in_pmd(long int vaddr)
  {
    for (pte& p: _pmd)
      if (p.get_pte_vaddr() == vaddr)
        return &p;

    return nullptr;
  }
};

int main()
{
  pmd p;
  p.add_in_pmd(1);
  pte* q = p.access_in_pmd(1);
  if(q != nullptr)
  {
    q->add_in_pte(10, 20);
  }
  p.add_in_pmd(2);  // no more error here
}
Thanks thmmm, to convert it change it using vectors.

I was still wondering, what could be the issue with my code. I tried adding copy cons, overload = but that didn't help.

Anyway, I will use vectors

Thanks

Update:

I made few more changes and using "rule of three/five/zero", it worked exactly it should work. :-)

Thank you so much. This is new knowledge I got.

Regards,
--
Amit
Last edited on
Topic archived. No new replies allowed.