Fix repo mapping lookup in runfiles library
Copybara Import from https://github.com/bazelbuild/rules_cc/pull/494
BEGIN_PUBLIC
Fix repo mapping lookup in runfiles library (#494)
The lookup of a prefix match in the repo mapping has to use "floor" semantics (largest element less or equal) and needs to check for bounds to avoid undefined behavior.
Closes #494
END_PUBLIC
COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_cc/pull/494 from fmeum:fix-msan-error ed21f4f75f5c6e240021c67a731118888b9a02c4
PiperOrigin-RevId: 810864188
Change-Id: I79d7b959e7e0e30c98cea8e87ec2d97236ae0eae
diff --git a/cc/runfiles/runfiles.cc b/cc/runfiles/runfiles.cc
index 2c27884..3f526d3 100644
--- a/cc/runfiles/runfiles.cc
+++ b/cc/runfiles/runfiles.cc
@@ -213,24 +213,29 @@
}
string target_apparent = path.substr(0, first_slash);
auto lookup_key = std::make_pair(target_apparent, source_repo);
- auto lower_bound = repo_mapping_.lower_bound(lookup_key);
- if (lower_bound->first == lookup_key) {
- return RlocationUnchecked(lower_bound->second + path.substr(first_slash),
+ // The smallest entry that is greater than lookup_key.
+ auto upper_bound = repo_mapping_.upper_bound(lookup_key);
+ // The largest entry that is less than or equal to lookup_key.
+ auto floor = upper_bound == repo_mapping_.begin() ? upper_bound
+ : std::prev(upper_bound);
+ if (floor == repo_mapping_.end()) {
+ return RlocationUnchecked(path, runfiles_map_, directory_);
+ }
+ if (floor->first == lookup_key) {
+ return RlocationUnchecked(floor->second + path.substr(first_slash),
runfiles_map_, directory_);
}
// Since the asterisk sorts before any other valid character in a repo name,
- // the previous element may be a prefix match.
- if (lower_bound != repo_mapping_.begin()) {
- std::pair<string, string> key;
- string value;
- std::tie(key, value) = *std::prev(lower_bound);
- if (key.first == target_apparent &&
- ends_with(key.second, "*") &&
- starts_with(
- source_repo, key.second.substr( 0, key.second.size() - 1))) {
- return RlocationUnchecked(
- value + path.substr(first_slash), runfiles_map_, directory_);
- }
+ // the floor element may be a prefix match.
+ std::pair<string, string> key;
+ string value;
+ std::tie(key, value) = *floor;
+ if (key.first == target_apparent &&
+ ends_with(key.second, "*") &&
+ starts_with(
+ source_repo, key.second.substr( 0, key.second.size() - 1))) {
+ return RlocationUnchecked(
+ value + path.substr(first_slash), runfiles_map_, directory_);
}
return RlocationUnchecked(path, runfiles_map_, directory_);
}