-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Ordering unimplemented ILVerify errors by their impact in compiler output validation #37393
Comments
CC: @jcouv @ArztSamuel @jkotas |
Thanks, that is very helpful! If I remember correctly the following ER specific errors are actually already reported, but with different names / messages:
Branching out of a finally block currently reports a
Branching into a catch/filter currently reports a
All three of these cases currently report a corresponding branch error. It shouldn't be too much work to change this to actually report a fallthrough error instead.
If I understand the PEVerify source correctly, this error was always reported, whenever an invalid leave target was found. When I implemented the checks for this, I also added a more specific error message for the different possible rule violations: I will be looking into the errors mentioned above and change the code / add test cases if necessary. I also hope to be able to have a quick look at the other errors soon and will comment here if I find anything worth noting. I think I remember that there are some other errors, which were defined in the PEVerify source, but never actually reported. |
Resolved |
Thanks!! I only used error list with assumption that if error is used then the scenario is most likely handled. The opposite is indeed not necessarily true. Yes I also find it odd that there is an error for leave outside handlers. I think it is defined as goto with clear eval stack. Could even be useful if it really works like that. Perhaps there is some subtle rule that makes it illegal, or it is a JIT implementation thing. Yes, I think it makes sense to continue using the error list for tracking and remove errors if corresponding scenarios are reported as something else. |
Yes, true. I forgot to mention that the evaluation stack is additionally cleared by the leave instruction.
PEVerify actually doesn't report a leave outside exception regions as an error (I have tested that). I have only seen this error being used for other rules of the leave instruction, like leaving out of a finally block. It is just the message that is kind of misleading. A note in ECMA (
|
I have had a quick look at all errors now:
I am not sure what this error was defined for in PEVerify. I couldn't find any code that actually reports this error. When the stack is poped even though it is empty, ILVerify reports
This error is never reported by PEVerify and I even found a comment in the source code saying: There is also a comment saying;
This error is never thrown inside the PEVerify code. PEVerify defined a flag to mark uninitialized ObjRefs, however this flag was only used to mark the this-pointer as uninitialized. I assume this error was defined for when an uninitialized ObjRef is returned, but was never used, since returning an uninitialized this-pointer was assigned its own error code.
This was reported by PEVerify when verifying compare instructions. I think
This error is only reported by PEVerify when a bool branch is performed with a value of type I wasn't able to find where quite a lot of errors are reported in PEVerify. I am not sure whether these errors are actually deprecated or simply reported in a code part that I do not have access to. Some of the errors definitiely sound like they still make sense though. Here is the full list of errors I could not find in the PEVerify source:
|
These errors are deprecated. The implementation of PEVerify morphed a lot over the years - they were likely used in the earlier versions of PEVerify and later removed. Could you please submit PR to cleanup all the unused errors?
Agree. BTW: I have run into nonsensical errors reported by PEVerify. I have tried to match PEVerify for some time to make side-by-side comparison of errors easier, and added a TODO to convert it to better error message later. I may be worth it to go over TODOs in ILVerify (to fix the error messages, and to find other non-implemented nugets). Opened dotnet/corert#4963 on this. |
Of course, done in dotnet/corert#4965. |
I also found some of the errors unfamiliar. I assumed they cover rare situations. Removing deprecated ones seems right thing to do |
//E_SIG_VAR_PARAM "Unrecognized type parameter of enclosing class." These seem to refer to situations when, for example, code references a method type parameter while the type parameter does not exist of containing method is not even generic. Such errors are relatively easy to hit in broken generic code. //E_PATH_LOC "Non-compatible types depending on path." I assume these were replaced by other errors about stack or expected type inconsistencies. //E_TRY_EQ_HND_FIL "Try and filter/handler blocks are equivalent." Interesting what happens if exception handling regions are incorrect as these errors mention. - other errors reported? //E_RET_UNINIT "Return uninitialized data." not sure how this even possible with //E_THIS_UNINIT_BR "Branch back when this is uninitialized." Did not know such rule exist(ed). I would guess, if there are actions that are disallowed when Curious - why is this ok now? |
These fall into the metadata validation errors. ILVerify does a basic validation as part of the type loading (you may not always get a pretty error for invalid metadata like this).
The ECMA spec has the backward branch rule that requires the verification to be a single pass. The implemented IL verification has not ever been single pass - the backward branch rule has not been ever enforced. |
Being an independent tool it may make sense for ILVerify be a single pass. It might actually be easier for the implementation. (by 1 pass i mean “logically 1 pass”, - I.E. not the kind that repeats the analysis once/if more data about backwards branches is discovered) Perhaps the backward branch rule for uninitialized ‘this’ should be enforced. It should not be hard and I doubt there are violations. |
I think we should make ILVerify compatible with PEVerify by default. I do not think there is much value in enforcing stronger rules than what PEVerify and JIT-time verification enforced since forever. It maybe ok to have a stronger rules in the opt-in warning mode: https://github.com/dotnet/corert/issues/3586 |
Talked with @jkotas about the "single pass" requirements in more details. ECMA335 does specify that
However no real implementation seem to be requiring this. We should review whether the requirement should be dropped from the spec. That said, some of these cases, while ok with the JIT and type-safety, are often indicative of bugs in IL generator. Besides, some rules are still enforced in 32bit JIT/PEVerify. I think we should keep the rules that result from one-pass requirement, at least those that 32bit PEVerify implements and make them "warnings" as in #37390 . In particular the rule described in |
Still wonder about the following. Are different errors reported for these? //E_TRY_EQ_HND_FIL "Try and filter/handler blocks are equivalent." |
As far as I am aware, the validation of the start/end offsets of exception regions is not implemented for ILVerify at all yet. It could well be that these errors are handled by other errors in PEVerify, but I think it would make sense to keep these errors in the list of this issue until we have unit tests for ILVerify confirming that these cases are handled appropriately. |
|
For cross reference: Mono currently requires that, see dotnet/corefx#39765. |
Also see https://github.com/dotnet/coreclr/issues/14492 for an example where different single pass implementations may arrive at different answers for types. |
I couldn't figure out the best area label to add to this issue. Please help me learn by adding exactly one area label. |
This is very subjective. Most unimplemented errors between
UnknownOpcode
andThisMismatch
in https://github.com/dotnet/corert/blob/master/src/ILVerify/src/VerifierError.cs are interesting.My approach here is to prioritize the errors by the chances of seeing such violation without triggering some internal asserts in our compilers.
Basically - bugs at higher levels of abstraction typically result in logically incorrect and yet valid IL, so IL verification cannot help there. However bugs at lower levels often result in malformed IL and that is where IL verification could be very helpful.
I would start with completing errors related to control flow, stack misbalances and uninitialized data. If IL is malformed due to a bug, it often ends up triggering these.
Many look already implemented, but there are still some not yet done.
Then there are bugs where something went wrong with dataflow or casts. In such cases we generally see various stack corruptions and mishaps with type compatibility.
The shape of exception handling regions could be delicate, but the area is not currently in active development so these can be done later.
The text was updated successfully, but these errors were encountered: