-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LLVM][Coverage][Unittest] Fix dangling reference in unittest #147118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
In loop of `writeAndReadCoverageRegions`, `OutputFunctions[I].Filenames` references to contents of `Filenames` after returning from `readCoverageRegions` but `Filenames` will be cleared in next call of `readCoverageRegions`, causes dangling reference. The lifetime of the contents of `Filenames` must be equal or longer than `OutputFunctions[I]`, thus it has been moved into `OutputFunctions[I]` (typed `OutputFunctionCoverageData`).
|
@llvm/pr-subscribers-pgo Author: Tomohiro Kashiwada (kikairoya) ChangesIn loop of Full diff: https://github.com/llvm/llvm-project/pull/147118.diff 1 Files Affected:
diff --git a/llvm/unittests/ProfileData/CoverageMappingTest.cpp b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
index ec81e5f274efa..59c381a1b4e82 100644
--- a/llvm/unittests/ProfileData/CoverageMappingTest.cpp
+++ b/llvm/unittests/ProfileData/CoverageMappingTest.cpp
@@ -64,6 +64,7 @@ namespace {
struct OutputFunctionCoverageData {
StringRef Name;
uint64_t Hash;
+ std::vector<std::string> FilenamesStorage;
std::vector<StringRef> Filenames;
std::vector<CounterMappingRegion> Regions;
std::vector<CounterExpression> Expressions;
@@ -71,8 +72,10 @@ struct OutputFunctionCoverageData {
OutputFunctionCoverageData() : Hash(0) {}
OutputFunctionCoverageData(OutputFunctionCoverageData &&OFCD)
- : Name(OFCD.Name), Hash(OFCD.Hash), Filenames(std::move(OFCD.Filenames)),
- Regions(std::move(OFCD.Regions)) {}
+ : Name(OFCD.Name), Hash(OFCD.Hash),
+ FilenamesStorage(std::move(OFCD.FilenamesStorage)),
+ Filenames(std::move(OFCD.Filenames)), Regions(std::move(OFCD.Regions)) {
+ }
OutputFunctionCoverageData(const OutputFunctionCoverageData &) = delete;
OutputFunctionCoverageData &
@@ -135,7 +138,6 @@ struct InputFunctionCoverageData {
struct CoverageMappingTest : ::testing::TestWithParam<std::tuple<bool, bool>> {
bool UseMultipleReaders;
StringMap<unsigned> Files;
- std::vector<std::string> Filenames;
std::vector<InputFunctionCoverageData> InputFunctions;
std::vector<OutputFunctionCoverageData> OutputFunctions;
@@ -233,13 +235,10 @@ struct CoverageMappingTest : ::testing::TestWithParam<std::tuple<bool, bool>> {
void readCoverageRegions(const std::string &Coverage,
OutputFunctionCoverageData &Data) {
- // We will re-use the StringRef in duplicate tests, clear it to avoid
- // clobber previous ones.
- Filenames.clear();
- Filenames.resize(Files.size() + 1);
+ Data.FilenamesStorage.resize(Files.size() + 1);
for (const auto &E : Files)
- Filenames[E.getValue()] = E.getKey().str();
- ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(Filenames);
+ Data.FilenamesStorage[E.getValue()] = E.getKey().str();
+ ArrayRef<std::string> FilenameRefs = llvm::ArrayRef(Data.FilenamesStorage);
RawCoverageMappingReader Reader(Coverage, FilenameRefs, Data.Filenames,
Data.Expressions, Data.Regions);
EXPECT_THAT_ERROR(Reader.read(), Succeeded());
|
|
Gentle ping. |
|
Oh, is this the cause of the failures of the ProfileData test failures on Cygwin? |
|
Yes. I got an expectation error, 3 vs 5. |
jeremyd2019
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'd appreciate another review from someone else because I don't have a firm handle on what's going on here
The fix looks reasonable, but I wonder why this issue hasn't been observed elsewhere. If I understand it correctly, this issue should be observable anywhere by building and running this unit test with address sanitizer, no? Or does it specifically require having the old libstdc++ CoW If the issue is having an |
Ideally, yes. If there were a sanitizer capable of detecting access to destroyed objects via a pseudo-destructor call, this issue should be detected. |
| StringRef Name; | ||
| uint64_t Hash; | ||
| std::vector<std::string> FilenamesStorage; | ||
| std::vector<StringRef> Filenames; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not store the strings directly in Filenames rather than having a separate storage?
| std::vector<StringRef> Filenames; | |
| std::vector<std::string> Filenames; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Filenames will be referenced by CoverageMappingRecord::Filenames, which is ArrayRef<StringRef>.
| Record.Filenames = Filenames; |
| // clobber previous ones. | ||
| Filenames.clear(); | ||
| Filenames.resize(Files.size() + 1); | ||
| Data.FilenamesStorage.resize(Files.size() + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why + 1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Files (filename to index map) uses 1-based index. I don't know why it does so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be good to say this in a comment to make it clear the +1 isn't a bug
|
Ping? I've lost track of the status of this... |
|
@ellishg Can you follow up here - any further objection to merging this? |
mstorsjo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, will merge soon if there's no further comments here.
Sorry I missed this. LGTM |
| // clobber previous ones. | ||
| Filenames.clear(); | ||
| Filenames.resize(Files.size() + 1); | ||
| Data.FilenamesStorage.resize(Files.size() + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be good to say this in a comment to make it clear the +1 isn't a bug
…47118) In loop of `writeAndReadCoverageRegions`, `OutputFunctions[I].Filenames` references to contents of `Filenames` after returning from `readCoverageRegions` but `Filenames` will be cleared in next call of `readCoverageRegions`, causes dangling reference. The lifetime of the contents of `Filenames` must be equal or longer than `OutputFunctions[I]`, thus it has been moved into `OutputFunctions[I]` (typed `OutputFunctionCoverageData`). (cherry picked from commit ca09801)
…47118) In loop of `writeAndReadCoverageRegions`, `OutputFunctions[I].Filenames` references to contents of `Filenames` after returning from `readCoverageRegions` but `Filenames` will be cleared in next call of `readCoverageRegions`, causes dangling reference. The lifetime of the contents of `Filenames` must be equal or longer than `OutputFunctions[I]`, thus it has been moved into `OutputFunctions[I]` (typed `OutputFunctionCoverageData`). (cherry picked from commit ca09801)
In loop of
writeAndReadCoverageRegions,OutputFunctions[I].Filenamesreferences to contents ofFilenamesafter returning fromreadCoverageRegionsbutFilenameswill be cleared in next call ofreadCoverageRegions, causes dangling reference.The lifetime of the contents of
Filenamesmust be equal or longer thanOutputFunctions[I], thus it has been moved intoOutputFunctions[I](typedOutputFunctionCoverageData).