We would not ensure that the error is consumed in the case that logging
is disabled. Ensure that we properly drop the error on the floor or we
would re-trigger the checked failure.
Details
- Reviewers
bulbazord sgraenitz labath - Commits
- rGd87cd45e4d85: PECOFF: consume errors properly
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | ||
---|---|---|
869–873 | If logging is enabled, we are moving from the same object twice, no? I think we should rethink the LLDB_LOG macro when it comes to errors.... :/ |
lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | ||
---|---|---|
869–873 | Yeah ... I was worried about that. |
lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | ||
---|---|---|
869–873 | I should mention that at least on MSVC I _can_ get away with it: ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found ObjectFilePECOFF::AppendFromExportTable - failed to get export table entry name: RVA 0x0 for export ordinal table not found |
lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | ||
---|---|---|
869–873 | https://godbolt.org/z/nj4r7K8hb UBSAN also seems to indicate it is permissible. |
lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp | ||
---|---|---|
869–873 | Moving from a standard library type leaves the original object in a "valid but unspecified" state. Do we make such guarantees about llvm::Errors? This is probably going to work "correctly" but I'm not sure what might go wrong. |
First of all, yes the existing code is incorrect. Thanks for looking into this. However, I am afraid this isn't the right solution.
In the if body you can not std::move() from err twice. I guess we have to do something like:
if (log) LLDB_LOG(...) else consumeError(...)
which resulted in a check failure under LLVM_ENABLE_ABI_BREAKING_CHANGES
You probably mean LLVM_ENABLE_ABI_BREAKING_CHECKS? For Error this enables logic to make sure the error was checked: https://github.com/llvm/llvm-project/blob/release/16.x/llvm/include/llvm/Support/Error.h#L724 I think your observation is a side effect of the issue you look at and has nothing to do with compiler optimizations like NRVO. If logging is off, the error isn't consumed.
Thanks for adding me in the loop. And thanks for looking into the fix, though this bit is a bit confusing to me:
Ensure that we explicitly indicate that we would like the move semantics
in the assignment. With MSVC 14.35.32215, the assignment would not
trigger a NVRO and copy constructor would be invoked
From https://llvm.org/doxygen/classllvm_1_1Error.html, llvm::Error has both copy constructor and copy assignment deleted, so I don't understand how a copy constructor could be invoked? I believe I followed https://llvm.org/docs/ProgrammersManual.html#recoverable-errors in handling the error, so if not having std::move there is really an issue, that page should also be updated.
But it is probably like @sgraenitz said, it is just an effect of the error not being consumed when logging is disabled.
If logging is enabled, we are moving from the same object twice, no?
In the if body you can not std::move() from err twice.
The doc comment of the move constructor/assignment does say "original error becomes a checked Success value, regardless of its original state" and it is exactly what happens in the code, so moving from the same error twice should be fine.
You probably mean LLVM_ENABLE_ABI_BREAKING_CHECKS? For Error this enables logic to make sure the error was checked: https://github.com/llvm/llvm-project/blob/release/16.x/llvm/include/llvm/Support/Error.h#L724 I think your observation is a side effect of the issue you look at and has nothing to do with compiler optimizations like NRVO. If logging is off, the error isn't consumed.
Yes, I did indeed mean checks and not changes. I had originally tried with only the consumption in the non-logging case, but that still seemed to abort similarly. Adding the std::move on the assignment for the conditional was also required for some reason.
I do wonder if we should keep the consume to be unconditional or not as @alvinhochun points out that llvm::Error does guarantee this behaviour.
Hmm, now I'm wondering if I had run the wrong binary, because I do remember that I somehow ended up running the wrong binary once or twice. Let's go with removing the confusing std::move in the if because that _shouldn't_ be needed.
I think it's a very good practice that objects in moved-from state will only ever get destroyed. While the move ctor itself has no preconditions and thus might be fine to call again, the implementation of consumeError() does inspect the object. This adds an unnecessary risk for UB. Please simply check the log state and call either fmt_consume() or consumeError(). Thanks.
If logging is enabled, we are moving from the same object twice, no?
I think we should rethink the LLDB_LOG macro when it comes to errors.... :/