...
Wiki Markup |
---|
This example from Kernighan and Ritchie \[[Kernighan 88|AA. Bibliography#Kernighan 88]\] shows both the incorrect and correct techniques for removing items from a linked list. The incorrect solution, clearly marked as wrong in the book, is bad because {{p}} is deallocated before the {{p->next}} is executed, so {{p->next}} reads memory that has already been deallocated. |
Code Block |
---|
|
for (p = head; p != NULL; p = p->next)
free(p);
|
...
Kernighan and Ritchie also show the correct solution. To correct this error, a reference to p->next
is stored in q
before freeing p
.
Code Block |
---|
|
for (p = head; p != NULL; p = q) {
q = p->next;
free(p);
}
head = NULL;
|
...
In this noncompliant code example, buff
is written to after it has been deallocated. These vulnerabilities can be easily exploited to run arbitrary code with the permissions of the vulnerable process and are seldom this obvious. Typically, dynamic memory allocations and deallocations are far removed, making it difficult to recognize and diagnose such problems.
Code Block |
---|
|
int main(int argc, const char *argv[]) {
char *buff;
buff = new char[BUFSIZ];
// ...
delete[] buff;
// ...
strncpy(buff, argv[1], BUFSIZ-1);
}
|
...
In this compliant solution the dynamically allocated memory isn't deallocated until it is no longer required.
Code Block |
---|
|
int main(int argc, const char *argv[]) {
char *buff;
buff = new char[BUFSIZ];
// ...
strncpy(buff, argv[1], BUFSIZ-1);
// ...
delete[] buff;
buff = nullptr;
}
|
...
In the following noncompliant code example, the dynamically allocated memory managed by the buff
object is accessed after it has been implicitly deallocated by the object's destructor.
Code Block |
---|
|
int main(int argc, const char *argv[]) {
const char *s = "";
if (1 < argc) {
std::unique_ptr<char[]> buff (new char [BUFSIZ]);
// ...
s = strncpy(buff.get(), argv[1], BUFSIZ-1);
}
std::cout << s << '\n';
}
|
...
In this compliant solution the lifetime of the buff
object extends past the point the memory managed by the object is accessed.
Code Block |
---|
|
int main(int argc, const char *argv[]) {
std::unique_ptr<char[]> buff;
const char *s = "";
if (1 < argc) {
buff.reset(new char [BUFSIZ]);
// ...
s = strncpy(buff.get(), argv[1], BUFSIZ-1);
}
std::cout << s << '\n';
}
|
...