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

AccessViolation with .NET 4.6 #21

Closed
Kittyfisto opened this issue Jun 19, 2017 · 4 comments
Closed

AccessViolation with .NET 4.6 #21

Kittyfisto opened this issue Jun 19, 2017 · 4 comments

Comments

@Kittyfisto
Copy link
Contributor

Kittyfisto commented Jun 19, 2017

While trying to create a test case for a different issue, I stumbled upon the following:

Patching the System.Windows.Input.Keyboard.IsKeyDown() function crashes with an System.AccessViolationException in a simple console application:

at Harmony.ILCopying.Memory.WriteByte(Int64 memory, Byte value)
at Harmony.ILCopying.Memory.WriteBytes(Int64 memory, Byte[] values)
at Harmony.ILCopying.Memory.WriteJump(Int64 memory, Int64 destination)
at Harmony.PatchFunctions.UpdateWrapper(MethodBase original, PatchInfo patchInfo)
at Harmony.PatchProcessor.Patch()
at Harmony.HarmonyInstance.b__6_0(Type type)
at Harmony.CollectionExtensions.Do[T](IEnumerable1 sequence, Action1 action)
at Harmony.HarmonyInstance.PatchAll(Assembly assembly)
at Console.App.Main() in C:\Users\Simon\Documents\Visual Studio 2015\Projects\Console\Console\App.cs:line 19
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()

I've attached a project that exhibits this problem on my computer.
Console.zip

So far I've found out that this access violation does NOT happen when I change the following variables:

  • Patch a non framework class (does this happen because the PresentationCore.dll assembly is part of the GAC and likely ngen'd?)
  • Execute the same code from within an nunit unit test in the Debug configuration: nunit.zip

For the moment I've got some questions that need answering in order to provide a fix for this issue, such as:

  • (Assuming the retrieved address is correct) Why is this function's code page write protected? Is it because the underlying image is ngen'd?
  • Is it enough to simply mess with VirtualProtect to change the corresponding pages to be writable?
  • Why does it only happen in some environments? The one provided by the nunit runner shouldn't differ as far as the .NET framework is concerned as both projects are targeting the same framework

I'll report back once I've made some progress, but any input is appreciated!

@Kittyfisto
Copy link
Contributor Author

I've had some more time to play around and found out that one can change the access rights of the page containing the memory that should be patched to execute read|write, which causes the access violation to no longer occur.

Although I've started working on a patch, I'm hesitant to submit a pull request as I've yet to find a way to write a test that actually fails consistently, pre-patch.

@pardeike
Copy link
Owner

Since I trust the tests done in the pull request, I copied over the fix to the main branch. This solves this issue.

@pardeike
Copy link
Owner

pardeike commented Apr 1, 2018

Just for completeness, I tried patching System.Windows.Input.Keyboard.IsKeyDown() from within a .Net 4 VisualStudio project with the latest version of Harmony and it works just fine:

### Harmony 1.1.0.0 started at 2018-04-01 12.05.08
### 
### Patch System.Windows.Input.Keyboard, Boolean IsKeyDown(System.Windows.Input.Key)
L_0000: Local var 0: System.Boolean
L_0000: ldc.i4 0
L_0005: stloc 0 (System.Boolean)
L_0006: call Void Prefix()
L_000b: call System.Windows.Input.KeyboardDevice get_PrimaryDevice()
L_0010: ldarg.0
L_0011: callvirt Boolean IsKeyDown(System.Windows.Input.Key)
L_0016: stloc 0 (System.Boolean)
L_0017: call Void Postfix()
L_001c: ldloc 0 (System.Boolean)
L_001d: ret
DONE

If you run in a more restricted enivronment like a webserver you might still hit the access violation. In that case, there is nothing you can do (since security enforces it).

@Kittyfisto
Copy link
Contributor Author

Just replaced my custom built with a build of your master branch. Still works like a charm, thanks!

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