Skip to content
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

Unable to patch methods which DeclaringType is null #445

Closed
GeorgyPorgy opened this issue Jan 3, 2022 · 10 comments
Closed

Unable to patch methods which DeclaringType is null #445

GeorgyPorgy opened this issue Jan 3, 2022 · 10 comments
Assignees

Comments

@GeorgyPorgy
Copy link

GeorgyPorgy commented Jan 3, 2022

Describe the bug

When a target method is resolved via Module.ResolveMethod(int Token) its DeclaringType property is null and future attempt to patch the method triggers "System.NullReferenceException: Object reference not set to an instance of an object" at CreateDynamicMethod(MethodBase original, String suffix, Boolean debug)

In fact, the problem described is similar to that described in an already closed ticket. : "Unable to patch methods located inside the GlobalType (aka. ) #235 "

To Reproduce
Steps to reproduce the behavior:

  1. Resolve a method inside the GlobalType via Module.ResolveMethod (int Token)
  2. Apply patch to it ( Transpiler type in my case )
  3. The last line in the Harmony debug log reports : ### Patch: static System.UInt32 MethodBlaBlaBla(System.Byte* arg1, System.Byte* arg2 , System.Int32 arg3, System.SByte* arg4, SomeStruct* arg5)
  4. The target app errors log reports :
    ERROR - System.NullReferenceException: Object reference not set to an instance of an object.
    at HarmonyLib.MethodPatcher.CreateDynamicMethod(MethodBase original, String suffix, Boolean debug)
    at HarmonyLib.MethodPatcher..ctor(MethodBase original, MethodBase source, List1 prefixes, List1 postfixes, List1 transpilers, List1 finalizers, Boolean debug)
    at HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
    at HarmonyLib.PatchProcessor.Patch()

Expected behavior
The patch gets applied.

Runtime environment (please complete the following information):

  • OS: Windows 10, 64bit
  • .NET version 4.7.2
  • Harmony version 2.2.0.0
@pardeike
Copy link
Owner

pardeike commented Jan 5, 2022

Can you please verify with master that the issue is solved and reopen it if it isn't?

@pardeike
Copy link
Owner

pardeike commented Jan 6, 2022

Ping @GeorgyPorgy

@GeorgyPorgy
Copy link
Author

I checked the behavior with the new changes and it seems some of the problems have already been fixed, but the patching has not yet ended successfully.
Patching work finished with following error : System.InvalidCastException: Unable to cast object of type 'ModifierType' to type 'System.Type'.

The last line in the Harmony debug log reports :
### Replacement: static System.UInt32 GLOBALTYPE::GLOBALTYPE.MethodBlaBlaBla(System.Byte* arg1, ....

while in the application log the messages list is as follows :
ERROR - System.InvalidCastException: Unable to cast object of type 'ModifierType' to type 'System.Type'.
at HarmonyLib.InlineSignatureParser.g__ReadTypeSignature|0_4(<>c__DisplayClass0_0& )
at HarmonyLib.InlineSignatureParser.g__ReadMethodSignature|0_0(InlineSignature method, <>c__DisplayClass0_0& )
at HarmonyLib.InlineSignatureParser.ImportCallSite(Module moduleFrom, Byte[] data)
at HarmonyLib.MethodBodyReader.ReadOperand(ILInstruction instruction)
at HarmonyLib.MethodBodyReader.ReadInstructions()
at HarmonyLib.MethodPatcher.CreateReplacement(Dictionary`2& finalInstructions)
at HarmonyLib.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
at HarmonyLib.PatchProcessor.Patch()

Runtime environment :

  • OS: Windows 10, 64bit
    
  • .NET version 4.7.2
    
  • Harmony version 2.2.0.0-master branch
    

@pardeike
Copy link
Owner

pardeike commented Jan 7, 2022

Right now, I can only guess the problem because I have no idea how to write a test for such a method. If you know a way to reference such a method in a test please let me know.

@pardeike pardeike reopened this Jan 7, 2022
@pardeike
Copy link
Owner

pardeike commented Jan 7, 2022

Also the stacktrace indicates that your original method has some very unusual IL codes that trigger the InlineSignature parser. Could you tell me more about your original method and maybe list it’s IL code. Parsing inline IL is still new and not much tested either and has nothing to do with the method being without type.

@pardeike
Copy link
Owner

pardeike commented Jan 7, 2022

On further inspection, the stacktrace isn’t helpful because there are several casts to Type that could fail so if you could be so kind to make your debugger stop at the exception and maybe give us some overview of what bytes the reader is reading, then me and @0x0ade who wrote the code can help you better.

@GeorgyPorgy
Copy link
Author

GeorgyPorgy commented Jan 8, 2022

Thanks for your efforts, Andreas.

The method IL code can be seen at the link below :
https://drive.google.com/file/d/1Jq3teFou0PC4ZW0jnGvxcAaMZopZGJYr/view?usp=sharing

The instruction list was generated with ILSpy.

I will attempt to extract additional information with the help of the debugger and provide it as soon as possible.

P.S.
I modified the function "ReadInstructions()" to log the information about the position of the currently processed instruction, but before analyzing its operand ...
The last reported number is 0x0019, which means that the exception occurs when processing the operand in the 'calli' instruction.

@pardeike
Copy link
Owner

At this point it is unclear if it is at all possible to create the correct result from this calli due to my possible limitations in the c# reflection api.

I spoke with @0x0ade and it looks like there might be a very convoluted way to support this but at this point it’s unclear if and who could implement this. It’s a rather difficult topic.

@GeorgyPorgy
Copy link
Author

Hello Andreas,

https://www.codeproject.com/Articles/1244372/Reflecting-Within-a-Method-Body
section 'InlineSig'

Would this article help us ?

regards

@pardeike
Copy link
Owner

That article just shows the basics. Our code here handles this case already:

case OperandType.InlineSig:

It’s the parser that fails the case because it is more complicated than the article suggests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants