This is an archive of the discontinued LLVM Phabricator instance.

[LLDB][NativePDB] Fix parameter size for member functions LF_MFUNCTION
ClosedPublic

Authored by zequanwu on Oct 18 2022, 4:09 PM.

Details

Summary

Fix the problem that it was treating member functions as non-member functions
when trying to get the parameter size. This causes some non-parameter variables
showing up in function signature. Suprisingly,
cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(...)) just sliently
parse it without error and gave the wrong result.

It's hard to test it. This only causes problem when params_remaining
is larger than the real parameter size. If it's smaller, we also check
individual local variable's attribute to see it's a parameter. When I trying to
come up with a test, the parameter size is always 0 if we parse LF_MFUNCTION as
LF_PROCEDURE.

Diff Detail

Event Timeline

zequanwu created this revision.Oct 18 2022, 4:09 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 18 2022, 4:09 PM
zequanwu requested review of this revision.Oct 18 2022, 4:09 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 18 2022, 4:09 PM
rnk added a comment.Oct 18 2022, 5:29 PM

Right, so cantFail must be an assertions-only check. That's not great. These deserialization APIs have really, really bad ergonomics and could use a lot of improvement if you want to look into that.

It would be really nice if, for example, this worked more like dyn_cast. Consider this kind of code:

CVType signature;
NewTypeMatcher d(signature);
if (auto *sig = d.getAs<ProcedureRecord>()) {
   ... handle ProcedureRecord
} else if (auto *sig = d.getAs<MemberFunctionRecord>()) {
  ... handle MemberFunctionRecord
}

Given what Reid said, would it be possible to make a test case that fails in an asserts build? Or was it maybe failing already there?

Right, so cantFail must be an assertions-only check. That's not great.

With assertion enabled, lldb still silently deserialize member functions as non-member functions. My guess is that TypeDeserializer::deserializeAs doesn't return error in this case since sizeof(MemberFunctionRecord) > sizeof(ProcedureRecord). We may need additional checking in TypeDeserializer::deserializeAs to verify that we are deserializing the correct type.

So if I understand correctly, when we deserialize incorrectly, this causes us to misclassify some function parameters (arguments) as local variables. Is that correct? If yes, then that is something that can be checked. Even if the misclassified variables behave perfectly, their kind is still visible, e.g. in the output of "frame variable --scope".

So if I understand correctly, when we deserialize incorrectly, this causes us to misclassify some function parameters (arguments) as local variables. Is that correct? If yes, then that is something that can be checked. Even if the misclassified variables behave perfectly, their kind is still visible, e.g. in the output of "frame variable --scope".

It's the opposite. Some non parameters local variables are misclassified as parameters, since deserialized parameter count is incorrect/larger. Those misclassified local variables will have the parameter bit set. See the inline comment for detail.

Or maybe we should just rely on individual variable's debug info to determine if a local var is parameter or not, not the parameter count found in function debug info.

lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
1825

Because we also check individual variable's debug info kind (parameter or not), if the deserialized parameter count number is smaller than actual number, this would fix it. So, it only causes problem when the deserialized result is larger which causes non-parameter local variables count as parameters.

The reason for this check, I vaguely remember, is that some function debug info has missing parameter count (e.g. 0), but the individual variable debug info says it's a parameter.

labath accepted this revision.Oct 27 2022, 7:13 AM

So if I understand correctly, when we deserialize incorrectly, this causes us to misclassify some function parameters (arguments) as local variables. Is that correct? If yes, then that is something that can be checked. Even if the misclassified variables behave perfectly, their kind is still visible, e.g. in the output of "frame variable --scope".

It's the opposite. Some non parameters local variables are misclassified as parameters, since deserialized parameter count is incorrect/larger. Those misclassified local variables will have the parameter bit set. See the inline comment for detail.

Ugh, yeah, carry on as you were.

Or maybe we should just rely on individual variable's debug info to determine if a local var is parameter or not, not the parameter count found in function debug info.

If it's sufficient, then yeah, definitely.

This revision is now accepted and ready to land.Oct 27 2022, 7:13 AM