We previously saw that the SkipVerification demand for calling a method with unverifiable code occurs at JIT time rather than at runtime. Two other types of demands also occur at JIT time, LinkDemands and InheritenceDemands. An InheritenceDemand will occur when the method of the derived class is being JITed, while a LinkDemand occurs when the method which calls the method containing the LinkDemand is being JITed. For instance, if method A calls method B, which has a LinkDemand for FullTrust, the demand occurs when A is JITed. If method C overrides a method in class D which is protected with an InheritenceDemand, the demand occurs when C is JITed.
This has some interesting consequences. Since the basic unit of JIT compilation is the method, you cannot have a single method which checks the permission set its running with, and then conditionally calls a method protected by a LinkDemand if if would satisfy that demand. Instead, it would have to check it’s permissions and if it had enough call another method which simply turned around and called the method with the LinkDemand. Similarly, you cannot do a try … catch(SecurityException) around a method protected by a LinkDemand.
I recently was asked a question about a program that stopped working when it was moved to a file share. The author of the application attempted handle this gracefully by displaying an error message to his users indicating that they need to increase the trust of the application. However, even that code didn’t help — it seemed as though the application’s Main method never even got to execute.
It turns out that Main created a Mutex object, and the Mutex constructor contains a LinkDemand for UnmanagedCode. Now that we know that this demand will occur at JIT time, the observed behavior seems understandable. When the JIT attempted to compile Main, it found a call to a method that had a LinkDemand for UnmanagedCode, and so checked the permission set of the assembly containing Main. It then found that this assembly did not have UnmanagedCode Permission, so it threw a SecurityException rather than compiling the method. This prevented the author’s attempt to fail gracefully from ever running, and the application died with an unhandled exception. In fact, since this occurred while JITing Main, there actually wasn’t even a call stack yet, so the exception message wasn’t even particularly helpful in tracking down the problem.
One way to fix this is to have Main first do the check for FullTrust, then call another method which does the work that used to occur in the original Main method. This way, the application’s entry point is allowed to JIT, and it can provide a useful diagnostic message to the users in the case that they need to provide extra trust for the code.