Skip to content

Commit ade181b

Browse files
authored
Honor lengths in merged named-data keys (pytorch#22977)
Summary: `NamedDataMap` keys are `string_view` values and are not required to be null terminated. Make merged-map lookup and logging honor the explicit key length, and fix an existing test comparison that compared a buffer with itself. Add coverage using a valid key followed by unrelated bytes. Reviewed By: rascani Differential Revision: D119537721 Pull Request resolved: pytorch#22977
1 parent 820086d commit ade181b

3 files changed

Lines changed: 50 additions & 14 deletions

File tree

‎extension/named_data_map/merged_data_map.cpp‎

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace ET_MERGED_DATA_MAP_NAMESPACE {
3737
"No non-empty named data maps provided to merge");
3838

3939
// Check for duplicate keys.
40-
std::unordered_map<std::string, uint32_t> key_to_map_index;
40+
KeyToMapIndex key_to_map_index;
4141
for (const uint32_t i : c10::irange(valid_data_maps.size())) {
4242
const auto cur_map = valid_data_maps[i];
4343
uint32_t num_keys = cur_map->get_num_keys().get();
@@ -47,7 +47,8 @@ namespace ET_MERGED_DATA_MAP_NAMESPACE {
4747
ET_CHECK_OR_RETURN_ERROR(
4848
inserted,
4949
InvalidArgument,
50-
"Duplicate key %s in named data maps at index %u and %" PRIu32,
50+
"Duplicate key %s in named data maps at index %" PRIu32
51+
" and %" PRIu32,
5152
cur_key,
5253
it->second,
5354
i);
@@ -58,19 +59,27 @@ namespace ET_MERGED_DATA_MAP_NAMESPACE {
5859

5960
ET_NODISCARD Result<const TensorLayout> MergedDataMap::get_tensor_layout(
6061
string_view key) const {
61-
const auto it = key_to_map_index_.find(key.data());
62+
const auto it = key_to_map_index_.find(key);
6263
if (it == key_to_map_index_.end()) {
63-
ET_LOG(Debug, "Key %s not found in named data maps.", key.data());
64+
ET_LOG(
65+
Debug,
66+
"Key %.*s not found in named data maps.",
67+
static_cast<int>(key.size()),
68+
key.data());
6469
return Error::NotFound;
6570
}
6671
return named_data_maps_.at(it->second)->get_tensor_layout(key);
6772
}
6873

6974
ET_NODISCARD
7075
Result<FreeableBuffer> MergedDataMap::get_data(string_view key) const {
71-
const auto it = key_to_map_index_.find(key.data());
76+
const auto it = key_to_map_index_.find(key);
7277
if (it == key_to_map_index_.end()) {
73-
ET_LOG(Debug, "Key %s not found in named data maps.", key.data());
78+
ET_LOG(
79+
Debug,
80+
"Key %.*s not found in named data maps.",
81+
static_cast<int>(key.size()),
82+
key.data());
7483
return Error::NotFound;
7584
}
7685
return named_data_maps_.at(it->second)->get_data(key);
@@ -80,11 +89,12 @@ ET_NODISCARD Error MergedDataMap::load_data_into(
8089
string_view key,
8190
void* buffer,
8291
size_t size) const {
83-
const auto it = key_to_map_index_.find(key.data());
92+
const auto it = key_to_map_index_.find(key);
8493
ET_CHECK_OR_RETURN_ERROR(
8594
it != key_to_map_index_.end(),
8695
NotFound,
87-
"Key %s not found in named data maps",
96+
"Key %.*s not found in named data maps",
97+
static_cast<int>(key.size()),
8898
key.data());
8999
return named_data_maps_.at(it->second)->load_data_into(key, buffer, size);
90100
}
@@ -98,7 +108,7 @@ ET_NODISCARD Result<const char*> MergedDataMap::get_key(uint32_t index) const {
98108
ET_CHECK_OR_RETURN_ERROR(
99109
index < total_num_keys,
100110
InvalidArgument,
101-
"Index %u out of range of size %u",
111+
"Index %" PRIu32 " out of range of size %" PRIu32,
102112
index,
103113
total_num_keys);
104114
for (auto i : c10::irange(named_data_maps_.size())) {

‎extension/named_data_map/merged_data_map.h‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <executorch/runtime/core/named_data_map.h>
1212

13+
#include <string_view>
1314
#include <unordered_map>
1415
#include <vector>
1516

@@ -92,10 +93,12 @@ class MergedDataMap final
9293
~MergedDataMap() override = default;
9394

9495
private:
96+
using KeyToMapIndex = std::unordered_map<std::string_view, uint32_t>;
97+
9598
MergedDataMap(
9699
std::vector<const executorch::ET_RUNTIME_NAMESPACE::NamedDataMap*>
97100
named_data_maps,
98-
std::unordered_map<std::string, uint32_t> key_to_map_index)
101+
KeyToMapIndex key_to_map_index)
99102
: named_data_maps_(std::move(named_data_maps)),
100103
key_to_map_index_(std::move(key_to_map_index)) {}
101104

@@ -107,8 +110,8 @@ class MergedDataMap final
107110
std::vector<const executorch::ET_RUNTIME_NAMESPACE::NamedDataMap*>
108111
named_data_maps_;
109112

110-
// Map from key to index in the named_data_maps_ vector.
111-
std::unordered_map<std::string, uint32_t> key_to_map_index_;
113+
// Keys alias stable storage owned by the wrapped, longer-lived data maps.
114+
KeyToMapIndex key_to_map_index_;
112115
};
113116

114117
} // namespace ET_MERGED_DATA_MAP_NAMESPACE

‎extension/named_data_map/test/merged_data_map_test.cpp‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616

1717
#include <gtest/gtest.h>
1818

19+
#include <cstring>
1920
#include <memory>
21+
#include <string>
2022
#include <unordered_map>
2123
#include <vector>
2224

@@ -120,8 +122,7 @@ void compare_ndm_api_calls(
120122
EXPECT_EQ(merged_load_into, Error::Ok);
121123
for (auto j : c10::irange(ndm_meta.nbytes())) {
122124
EXPECT_EQ(
123-
((uint8_t*)merged_buffer.get())[j],
124-
((uint8_t*)merged_buffer.get())[j]);
125+
((uint8_t*)ndm_buffer.get())[j], ((uint8_t*)merged_buffer.get())[j]);
125126
}
126127
}
127128
}
@@ -171,3 +172,25 @@ TEST_F(MergedDataMapTest, CheckDataMapContents) {
171172
compare_ndm_api_calls(data_maps_["addmul"].get(), &merged_map.get());
172173
compare_ndm_api_calls(data_maps_["linear"].get(), &merged_map.get());
173174
}
175+
176+
TEST_F(MergedDataMapTest, LookupUsesStringViewLength) {
177+
std::vector<const NamedDataMap*> ndms = {data_maps_["addmul"].get()};
178+
Result<MergedDataMap> merged_map =
179+
MergedDataMap::load(Span<const NamedDataMap*>(ndms.data(), ndms.size()));
180+
ASSERT_EQ(merged_map.error(), Error::Ok);
181+
182+
const char* key = data_maps_["addmul"]->get_key(0).get();
183+
const size_t key_size = std::strlen(key);
184+
const std::string storage = std::string(key) + ".not-part-of-key";
185+
const std::string_view bounded_key(storage.data(), key_size);
186+
187+
EXPECT_EQ(merged_map->get_data(bounded_key).error(), Error::Ok);
188+
EXPECT_EQ(merged_map->get_tensor_layout(bounded_key).error(), Error::Ok);
189+
const auto layout = merged_map->get_tensor_layout(bounded_key);
190+
ASSERT_EQ(layout.error(), Error::Ok);
191+
const size_t data_size = layout->nbytes();
192+
auto buffer = std::make_unique<uint8_t[]>(data_size);
193+
EXPECT_EQ(
194+
merged_map->load_data_into(bounded_key, buffer.get(), data_size),
195+
Error::Ok);
196+
}

0 commit comments

Comments
 (0)