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

Aug 17, 2021 at 2:42pm
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 Aug 17, 2021 at 5:29pm
Aug 17, 2021 at 4:42pm
Please post
formatted
code so that it is readable!

Use:

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

Aug 17, 2021 at 5:29pm
Thanks, I had changed it.
Aug 17, 2021 at 5:43pm
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 ?
Aug 17, 2021 at 5:52pm
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 Aug 17, 2021 at 5:56pm
Aug 18, 2021 at 12:14am
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 Aug 18, 2021 at 12:16am
Aug 18, 2021 at 4:41am
Another problem I see is that the "Rule of 5 is not followed"
https://en.cppreference.com/w/cpp/language/rule_of_three
Aug 18, 2021 at 5:33am
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
}
Aug 18, 2021 at 6:17am
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 Aug 18, 2021 at 7:37am
Topic archived. No new replies allowed.