大小 4 的读取无效?
Invalid Read of Size 4?
我在一个程序中 运行 valgrind,虽然程序执行得很好,但 valgrind 报告:
==6542== Invalid read of size 4
==6542== at 0x8049C6F: Table::removeWebsite(Table&) (Table.cpp:146)
==6542== by 0x8049768: main (app.cpp:140)
==6542== Address 0x43f87d4 is 4 bytes inside a block of size 8 free'd
==6542== at 0x402B528: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-x86-linux.so)
==6542== by 0x8049BB0: Table::removeWebsite(Table&) (Table.cpp:124)
==6542== by 0x8049768: main (app.cpp:140)
我不完全确定哪里出了问题。这是 valgrind 指向的代码...
bool Table::removeWebsite(Table& parm)
{
bool flag = false; //flag to show if an item is removed or not
int OriTableSize = currCapacity;
for (int index = 0; index < OriTableSize; index++) //search through array list, starting at index
{
Node *current = parm.aTable[index];
Node *prev = nullptr;
while (current != nullptr) //search through linked lists at array[index]
{
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
delete current;
size--;
parm.aTable[index] = nullptr;
flag = true;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
delete current;
size--;
flag = true;
}
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
delete current;
size--;
flag = true;
}
}
prev = current;
current = current->next; //go to next position in linked list
}
}
if (flag == true)//at least one item was removed
return true;
else
return false;
}
那个"delete current"指向一个节点,它有:
struct Node
{
Node(const SavedWebsites& parm)
{
data = new SavedWebsites(parm);
next = nullptr;
};
~Node()
{
delete data;
next = nullptr;
}
SavedWebsites *data;
Node *next;
};
并且 SavedWebsites 中的数据具有析构函数:
//Default Destructor
SavedWebsites::~SavedWebsites()
{
if (this->topic)
{
delete [] this->topic;
this->topic = nullptr;
}
if (this->website)
{
delete [] this->website;
this->website = nullptr;
}
if (this->summary)
{
delete [] this->summary;
this->summary = nullptr;
}
if (this->review)
{
delete [] this->review;
this->review = nullptr;
}
rating = 0;
}
*注意项目 "topic" "website" "summary" 和 "review" 都是用
创建的
... = new char[strlen(topic)+1] //(We have to use Cstrings)
我对这一切还很陌生,所以对可能导致此 valgrind 无效读取的原因有什么想法吗?
您没有指出哪一行对应于 Table.cpp:146
,但根据 Valgrind 的输出,看起来有问题的分配代表一个 Node
实例,因为 8 个字节的大小匹配(假设32 位系统)。无效读取是由该实例的偏移量 4 和大小 4 触发的,因此这必须对应于成员 next
.
Table.cpp:146:
current = current->next; //go to next position in linked list
如果在迭代中出现 delete
,则之后访问已删除的节点 current
。您还根据无效指针初始化 prev
,因此在删除的情况下,最后一个有效节点的 next
指针将不会正确更新。
您的代码似乎工作正常(但不是),因为它的行为取决于使用的分配器和其他分配。如果分配器要用某种模式填充释放的内存,或者如果该内存被立即重用并写入,您会看到分段错误。
为了解决这个问题,我会推迟 delete
。在下一次迭代之前,您可以读取下一个节点并删除原始 current
或更新 prev
并读取下一个节点。
bool del = false;
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
parm.aTable[index] = nullptr;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
}
del = true;
flag = true;
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
del = true
flag = true;
}
}
if (del)
{
Node *deletenode = current;
current = current->next;
delete deletenode;
size--;
}
else
{
prev = current;
current = current->next; //go to next position in linked list
}
我在一个程序中 运行 valgrind,虽然程序执行得很好,但 valgrind 报告:
==6542== Invalid read of size 4
==6542== at 0x8049C6F: Table::removeWebsite(Table&) (Table.cpp:146)
==6542== by 0x8049768: main (app.cpp:140)
==6542== Address 0x43f87d4 is 4 bytes inside a block of size 8 free'd
==6542== at 0x402B528: operator delete(void*) (in /usr/lib64/valgrind/vgpreload_memcheck-x86-linux.so)
==6542== by 0x8049BB0: Table::removeWebsite(Table&) (Table.cpp:124)
==6542== by 0x8049768: main (app.cpp:140)
我不完全确定哪里出了问题。这是 valgrind 指向的代码...
bool Table::removeWebsite(Table& parm)
{
bool flag = false; //flag to show if an item is removed or not
int OriTableSize = currCapacity;
for (int index = 0; index < OriTableSize; index++) //search through array list, starting at index
{
Node *current = parm.aTable[index];
Node *prev = nullptr;
while (current != nullptr) //search through linked lists at array[index]
{
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
delete current;
size--;
parm.aTable[index] = nullptr;
flag = true;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
delete current;
size--;
flag = true;
}
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
delete current;
size--;
flag = true;
}
}
prev = current;
current = current->next; //go to next position in linked list
}
}
if (flag == true)//at least one item was removed
return true;
else
return false;
}
那个"delete current"指向一个节点,它有:
struct Node
{
Node(const SavedWebsites& parm)
{
data = new SavedWebsites(parm);
next = nullptr;
};
~Node()
{
delete data;
next = nullptr;
}
SavedWebsites *data;
Node *next;
};
并且 SavedWebsites 中的数据具有析构函数:
//Default Destructor
SavedWebsites::~SavedWebsites()
{
if (this->topic)
{
delete [] this->topic;
this->topic = nullptr;
}
if (this->website)
{
delete [] this->website;
this->website = nullptr;
}
if (this->summary)
{
delete [] this->summary;
this->summary = nullptr;
}
if (this->review)
{
delete [] this->review;
this->review = nullptr;
}
rating = 0;
}
*注意项目 "topic" "website" "summary" 和 "review" 都是用
创建的... = new char[strlen(topic)+1] //(We have to use Cstrings)
我对这一切还很陌生,所以对可能导致此 valgrind 无效读取的原因有什么想法吗?
您没有指出哪一行对应于 Table.cpp:146
,但根据 Valgrind 的输出,看起来有问题的分配代表一个 Node
实例,因为 8 个字节的大小匹配(假设32 位系统)。无效读取是由该实例的偏移量 4 和大小 4 触发的,因此这必须对应于成员 next
.
Table.cpp:146:
current = current->next; //go to next position in linked list
如果在迭代中出现 delete
,则之后访问已删除的节点 current
。您还根据无效指针初始化 prev
,因此在删除的情况下,最后一个有效节点的 next
指针将不会正确更新。
您的代码似乎工作正常(但不是),因为它的行为取决于使用的分配器和其他分配。如果分配器要用某种模式填充释放的内存,或者如果该内存被立即重用并写入,您会看到分段错误。
为了解决这个问题,我会推迟 delete
。在下一次迭代之前,您可以读取下一个节点并删除原始 current
或更新 prev
并读取下一个节点。
bool del = false;
if (current->data->getRating() == 1) //search ratings for 1
{
if (prev == nullptr) //if current is the start of the list
{
if (current->next == nullptr) //if current is the only item in this list
{
parm.aTable[index] = nullptr;
}
else
{
parm.aTable[index] = current->next; //point to the next item in list
}
del = true;
flag = true;
}
else //reset prev->next pointer to skip current
{
prev->next = current->next;
del = true
flag = true;
}
}
if (del)
{
Node *deletenode = current;
current = current->next;
delete deletenode;
size--;
}
else
{
prev = current;
current = current->next; //go to next position in linked list
}