...
In this compliant solution, the dynamically allocated memory is not deallocated until it is no longer required:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <new>
struct S {
void f();
};
void g() noexcept(false) {
S *s = new S;
// ...
s->f();
delete s;
} |
...
When possible, use automatic storage duration instead of dynamic storage duration. Since s is not required to live beyond the scope of g(), this compliant solution uses automatic storage duration to limit the lifetime of s to the scope of g():.
| Code Block | ||||
|---|---|---|---|---|
| ||||
struct S {
void f();
};
void g() {
S s;
// ...
s.f();
} |
...
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 | ||||
|---|---|---|---|---|
| ||||
#include <iostream>
#include <memory>
#include <cstring>
int main(int argc, const char *argv[]) {
const char *s = "";
if (argc > 1) {
enum { BufferSize = 32 };
try {
std::unique_ptr<char[]> buff(new char[BufferSize]);
std::memset(buff.get(), 0, BufferSize);
// ...
s = std::strncpy(buff.get(), argv[1], BufferSize - 1);
} catch (std::bad_alloc &) {
// Handle error
}
}
std::cout << s << std::endl;
}
|
...
In this compliant solution, the lifetime of the buff object extends past the point at which the memory managed by the object is accessed:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <iostream>
#include <memory>
#include <cstring>
int main(int argc, const char *argv[]) {
std::unique_ptr<char[]> buff;
const char *s = "";
if (argc > 1) {
enum { BufferSize = 32 };
try {
buff.reset(new char[BufferSize]);
std::memset(buff.get(), 0, BufferSize);
// ...
s = std::strncpy(buff.get(), argv[1], BufferSize - 1);
} catch (std::bad_alloc &) {
// Handle error
}
}
std::cout << s << std::endl;
}
|
...
In this compliant solution, a variable with automatic storage duration of type std::string is used in place of the std::unique_ptr<char[]>, which reduces the complexity and improves the security of the solution:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <iostream>
#include <string>
int main(int argc, const char *argv[]) {
std::string str;
if (argc > 1) {
str = argv[1];
}
std::cout << str << std::endl;
} |
...
In this compliant solution, a local copy of the string returned by str_func() is made to ensure that string str will be valid when the call to display_string() is made:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <string>
std::string str_func();
void display_string(const char *s);
void f() {
std::string str = str_func();
const char *cstr = str.c_str();
display_string(cstr); /* ok */
} |
...
The compliant solution depends on programmer intent. If the programmer intends to allocate a single unsigned char object, the compliant solution is to use new instead of a direct call to operator new(), as this compliant solution demonstrates:.
| Code Block | ||||
|---|---|---|---|---|
| ||||
void f() noexcept(false) {
unsigned char *ptr = new unsigned char;
*ptr = 0;
// ...
delete ptr;
} |
...