Skip to content

Commit 2175a8f

Browse files
Avoid manual lifetime management of std::string
This change touches several places in `Source` and `Storage` where string was being passed as a pointer, with expectations for `delete` to be called once done with the value. There may even be a case in Chromium at the moment where one of these calls may be leaking memory due to how the memory is expected to managed. This change passes the string by value, and in cases where the value may be omitted the string is wrapped on a `std::optional`. Bug: 423542167
1 parent 93ab6cc commit 2175a8f

16 files changed

Lines changed: 64 additions & 83 deletions

cpp/include/libaddressinput/null_storage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class NullStorage : public Storage {
3535
~NullStorage() override;
3636

3737
// No-op.
38-
void Put(const std::string& key, std::string* data) override;
38+
void Put(const std::string& key, std::string data) override;
3939

4040
// Always calls the |data_ready| callback function signaling failure.
4141
void Get(const std::string& key, const Callback& data_ready) const override;

cpp/include/libaddressinput/source.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include <libaddressinput/callback.h>
2323

24+
#include <optional>
2425
#include <string>
2526

2627
namespace i18n {
@@ -41,7 +42,7 @@ namespace addressinput {
4142
class Source {
4243
public:
4344
using Callback =
44-
i18n::addressinput::Callback<const std::string&, std::string*>;
45+
i18n::addressinput::Callback<const std::string&, std::optional<std::string>>;
4546

4647
virtual ~Source() = default;
4748

cpp/include/libaddressinput/storage.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <libaddressinput/callback.h>
2222

2323
#include <string>
24+
#include <optional>
2425

2526
namespace i18n {
2627
namespace addressinput {
@@ -45,13 +46,13 @@ namespace addressinput {
4546
class Storage {
4647
public:
4748
using Callback =
48-
i18n::addressinput::Callback<const std::string&, std::string*>;
49+
i18n::addressinput::Callback<const std::string&, std::optional<std::string>>;
4950

5051
virtual ~Storage() = default;
5152

5253
// Stores |data| for |key|, where |data| is an object allocated on the heap,
5354
// which Storage takes ownership of.
54-
virtual void Put(const std::string& key, std::string* data) = 0;
55+
virtual void Put(const std::string& key, std::string data) = 0;
5556

5657
// Retrieves the data for |key| and invokes the |data_ready| callback.
5758
virtual void Get(const std::string& key,

cpp/src/null_storage.cc

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,11 @@ namespace addressinput {
2424
NullStorage::NullStorage() = default;
2525
NullStorage::~NullStorage() = default;
2626

27-
void NullStorage::Put(const std::string& key, std::string* data) {
28-
assert(data != nullptr); // Sanity check.
29-
delete data;
30-
}
27+
void NullStorage::Put(const std::string& key, std::string data) {}
3128

3229
void NullStorage::Get(const std::string& key,
3330
const Callback& data_ready) const {
34-
data_ready(false, key, nullptr);
31+
data_ready(false, key, std::nullopt);
3532
}
3633

3734
} // namespace addressinput

cpp/src/retriever.cc

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,38 +56,35 @@ class Helper {
5656

5757
void OnValidatedDataReady(bool success,
5858
const std::string& key,
59-
std::string* data) {
59+
std::optional<std::string> data) {
6060
if (success) {
61-
assert(data != nullptr);
61+
assert(data != std::nullopt);
6262
retrieved_(success, key, *data);
6363
delete this;
6464
} else {
6565
// Validating storage returns (false, key, stale-data) for valid but stale
6666
// data. If |data| is empty, however, then it's either missing or invalid.
67-
if (data != nullptr && !data->empty()) {
68-
stale_data_ = *data;
67+
if (data.has_value() && !data->empty()) {
68+
stale_data_ = std::move(data).value();
6969
}
7070
source_.Get(key, *fresh_data_ready_);
7171
}
72-
delete data;
7372
}
7473

7574
void OnFreshDataReady(bool success,
7675
const std::string& key,
77-
std::string* data) {
76+
std::optional<std::string> data) {
7877
if (success) {
79-
assert(data != nullptr);
78+
assert(data.has_value());
8079
retrieved_(true, key, *data);
81-
storage_->Put(key, data);
82-
data = nullptr; // Deleted by Storage::Put().
80+
storage_->Put(key, std::move(data).value());
8381
} else if (!stale_data_.empty()) {
8482
// Reuse the stale data if a download fails. It's better to have slightly
8583
// outdated validation rules than to suddenly lose validation ability.
8684
retrieved_(true, key, stale_data_);
8785
} else {
8886
retrieved_(false, key, std::string());
8987
}
90-
delete data;
9188
delete this;
9289
}
9390

cpp/src/validating_storage.cc

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,20 +51,18 @@ class Helper {
5151

5252
void OnWrappedDataReady(bool success,
5353
const std::string& key,
54-
std::string* data) {
54+
std::optional<std::string> data) {
5555
if (success) {
56-
assert(data != nullptr);
56+
assert(data != std::nullopt);
5757
bool is_stale =
58-
!ValidatingUtil::UnwrapTimestamp(data, std::time(nullptr));
59-
bool is_corrupted = !ValidatingUtil::UnwrapChecksum(data);
58+
!ValidatingUtil::UnwrapTimestamp(&*data, std::time(nullptr));
59+
bool is_corrupted = !ValidatingUtil::UnwrapChecksum(&*data);
6060
success = !is_corrupted && !is_stale;
6161
if (is_corrupted) {
62-
delete data;
63-
data = nullptr;
62+
data = std::nullopt;
6463
}
6564
} else {
66-
delete data;
67-
data = nullptr;
65+
data = std::nullopt;
6866
}
6967
data_ready_(success, key, data);
7068
delete this;
@@ -83,10 +81,9 @@ ValidatingStorage::ValidatingStorage(Storage* storage)
8381

8482
ValidatingStorage::~ValidatingStorage() = default;
8583

86-
void ValidatingStorage::Put(const std::string& key, std::string* data) {
87-
assert(data != nullptr);
88-
ValidatingUtil::Wrap(std::time(nullptr), data);
89-
wrapped_storage_->Put(key, data);
84+
void ValidatingStorage::Put(const std::string& key, std::string data) {
85+
ValidatingUtil::Wrap(std::time(nullptr), &data);
86+
wrapped_storage_->Put(key, std::move(data));
9087
}
9188

9289
void ValidatingStorage::Get(const std::string& key,

cpp/src/validating_storage.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class ValidatingStorage : public Storage {
4444
~ValidatingStorage() override;
4545

4646
// Storage implementation.
47-
void Put(const std::string& key, std::string* data) override;
47+
void Put(const std::string& key, std::string data) override;
4848

4949
// Storage implementation.
5050
// If the data is invalid, then |data_ready| will be called with (false, key,

cpp/test/fake_storage.cc

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,13 @@ namespace addressinput {
2323

2424
FakeStorage::FakeStorage() = default;
2525

26-
FakeStorage::~FakeStorage() {
27-
for (const auto& pair : data_) {
28-
delete pair.second;
29-
}
30-
}
26+
FakeStorage::~FakeStorage() = default;
3127

32-
void FakeStorage::Put(const std::string& key, std::string* data) {
33-
assert(data != nullptr);
34-
auto result = data_.emplace(key, data);
28+
void FakeStorage::Put(const std::string& key, std::string data) {
29+
auto result = data_.emplace(key, std::move(data));
3530
if (!result.second) {
3631
// Replace data in existing entry for this key.
37-
delete result.first->second;
38-
result.first->second = data;
32+
result.first->second = std::move(data);
3933
}
4034
}
4135

@@ -44,7 +38,7 @@ void FakeStorage::Get(const std::string& key,
4438
auto data_it = data_.find(key);
4539
bool success = data_it != data_.end();
4640
data_ready(success, key,
47-
success ? new std::string(*data_it->second) : nullptr);
41+
success ? std::make_optional<std::string>(data_it->second) : std::nullopt);
4842
}
4943

5044
} // namespace addressinput

cpp/test/fake_storage.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,11 @@ class FakeStorage : public Storage {
6565
~FakeStorage() override;
6666

6767
// Storage implementation.
68-
void Put(const std::string& key, std::string* data) override;
68+
void Put(const std::string& key, std::string data) override;
6969
void Get(const std::string& key, const Callback& data_ready) const override;
7070

7171
private:
72-
std::map<std::string, std::string*> data_;
72+
std::map<std::string, std::string> data_;
7373
};
7474

7575
} // namespace addressinput

cpp/test/fake_storage_test.cc

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,12 @@ class FakeStorageTest : public testing::Test {
5050
const std::unique_ptr<const Storage::Callback> data_ready_;
5151

5252
private:
53-
void OnDataReady(bool success, const std::string& key, std::string* data) {
54-
ASSERT_FALSE(success && data == nullptr);
53+
void OnDataReady(bool success, const std::string& key, std::optional<std::string> data) {
54+
ASSERT_FALSE(success && !data.has_value());
5555
success_ = success;
5656
key_ = key;
57-
if (data != nullptr) {
58-
data_ = *data;
59-
delete data;
57+
if (data.has_value()) {
58+
data_ = std::move(data).value();
6059
}
6160
}
6261
};
@@ -70,7 +69,7 @@ TEST_F(FakeStorageTest, GetWithoutPutReturnsEmptyData) {
7069
}
7170

7271
TEST_F(FakeStorageTest, GetReturnsWhatWasPut) {
73-
storage_.Put("key", new std::string("value"));
72+
storage_.Put("key", std::string("value"));
7473
storage_.Get("key", *data_ready_);
7574

7675
EXPECT_TRUE(success_);
@@ -79,8 +78,8 @@ TEST_F(FakeStorageTest, GetReturnsWhatWasPut) {
7978
}
8079

8180
TEST_F(FakeStorageTest, SecondPutOverwritesData) {
82-
storage_.Put("key", new std::string("bad-value"));
83-
storage_.Put("key", new std::string("good-value"));
81+
storage_.Put("key", std::string("bad-value"));
82+
storage_.Put("key", std::string("good-value"));
8483
storage_.Get("key", *data_ready_);
8584

8685
EXPECT_TRUE(success_);

0 commit comments

Comments
 (0)