1

Closed

Injected containers are not working when registry keys are missing

description

I have just tried to get injected containers working, after two hours with no success I added the registry key for tracing and all of a sudden it was working like a charm.

After trying to investigate the issue it seems it's not working when the subkey HKCU\Software\Softpark\LibZ is missing, it doesn't seem to matter if the actual value is there or not. Adding the subkey HKLM\Software\Softpark\LibZ makes no difference. Maybe it's a security permission issue?

Steps to reproduce:
Create container
Inject libz into assembly
Instrument assembly
Remove HKCU\Software\Softpark\LibZ
Run assembly
Closed Apr 23, 2014 at 10:15 PM by Krashan
Fixed in 1.1.0.2 (most likely)

comments

Krashan wrote Apr 22, 2014 at 8:18 AM

I looked into it, followed the steps and couldn't reproduce. It is possible that not tracing itself helps, but if tracing is on some timings change and the causes the problem/fixes the problem (race condition?).
Is it possible that prepare mini working example (including script you use to build final executable)?

DavidZidar wrote Apr 22, 2014 at 8:53 AM

Alright, I'll try and prepare a minimal sample that reproduces the issue as soon as I'm able.

DavidZidar wrote Apr 22, 2014 at 8:59 PM

This was a tough one, I haven't exactly been able to reproduce the problem in a small sample project. But I noticed one specific issue at least.

To get to the bottom of this I used dotPeek as a symbol server so I could debug your code, and to my surprise it worked just fine when I had the debugger attached and stepped through the code line by line.

Then all of a sudden I got a CryptographicException in LibZ.Bootstrap.Internal.Hash. I see you are using a static instance of MD5 there, that's not good if it's not protected with a lock since MD5 is not thread safe.

This could cause an issue if multiple threads are loading assemblies at the same time.

However, I am still not sure why adding the registry key makes it work on my machine.

Krashan wrote Apr 22, 2014 at 9:38 PM

It might be related. Maybe having or not having trace changes some timings so it might hide or reveal some multi-threading issues.
I'll fix the MD5 issue, though.

DavidZidar wrote Apr 22, 2014 at 9:59 PM

Great! I'll try it again when the MD5 issue is fixed.

Krashan wrote Apr 22, 2014 at 11:01 PM

Addressed (hopefully) in 1.1.0.1

DavidZidar wrote Apr 22, 2014 at 11:19 PM

Thanks, the CryptographicException is gone now but my main issue still remains.

I'm stumped, I can't use the trace info because it works just fine when I add the reg key, and adding any sort of breakpoints in LibZResolver.Resolve makes it work fine as well. There must be some sort of multi threading issue still.

I guess I'm going to have make my own build of LibZ so I can instrument it myself and hopefully track down the issue.

Krashan wrote Apr 23, 2014 at 6:51 AM

Going back to the initial issue.
How it doesn't work? Throws exception? Blue screen? Fails silently?
How do you instrument executable?

DavidZidar wrote Apr 23, 2014 at 7:50 AM

It is throwing file not found exceptions, meaning it is unable to load my assemblies.

I guess I will just add a bunch of logging to see where it might be going wrong. My main suspect is the static constructor in the helper logger class since it instantly works without issues when I add the registry key, without the key it is doing four try/catches.

Static constructors are generally not the best place to do work, if anything goes wrong you get TypeLoaderExceptions for the remainder of the AppDomain lifetime. A better option may be a Lazy<> static member.

I'll get back when I've had some more time to investigate, it might not even be the static constructor.

Krashan wrote Apr 23, 2014 at 8:08 AM

Is it possible you send me (PM + dropbox) assemblies which cause the issue + libz build script?
I know there are IP issues, but I promise I won't start selling your stuff.

Krashan wrote Apr 23, 2014 at 9:27 AM

Which file is reported as FileNotFound? One of yours? or LibZ.Bootstrap?

DavidZidar wrote Apr 23, 2014 at 10:21 AM

Not LibZ.Bootstrap. It's whichever file that should be loaded first from the container, it's either mine or some third party lib I include depending on how much code I rip out of my startup class when testing.

I'll get back later about an assembly and build script, can't right now.

Krashan wrote Apr 23, 2014 at 10:53 AM

And another one. You are saying "injected containers". What about not-injected containers? Does the problem persist? You know, every bit of information can be a clue.

DavidZidar wrote Apr 23, 2014 at 11:13 AM

Just did a quick test with the container in an external file, seems to load just fine.

DavidZidar wrote Apr 23, 2014 at 11:13 AM

With the container as an external file I mean.

DavidZidar wrote Apr 23, 2014 at 5:42 PM

Now I've spent hours on this and I'm still not sure what is going wrong or what the difference is between using a file container or a resource container, they both seem to call the Helpers class which triggers the static constructor.

However, with a simple change in GetRegistryDWORD from:

return Convert.ToUInt32(root.OpenSubKey(path, false).GetValue(name));

To:

var subKey = root.OpenSubKey(path, false);
return subKey != null ? Convert.ToUInt32(subKey.GetValue(name)) : (uint?)null;

So it no longer throws unnecessary null reference exceptions then the issue seems to go away and everything is loading as it should.

Krashan wrote Apr 23, 2014 at 6:23 PM

It's strange that this cause the problem (NullReferenceException) as the whole GetRegistryDWORD is in try/catch all block.

But, if you say it help, let's assume it does.

DavidZidar wrote Apr 23, 2014 at 6:34 PM

Yes, I agree that it is strange. I can still prepare an assembly if you want to verify it yourself.

Krashan wrote Apr 23, 2014 at 6:54 PM

Yup. I would like to take a look. I'm still worried that something is wrong when multiple threads are trying to access the resolver and the fix is not actually a fix, it just changes some timings so the actual problem gets hidden.

DavidZidar wrote Apr 23, 2014 at 7:08 PM

I'm not sure how to PM you though, can't find any contact info.

Krashan wrote Apr 23, 2014 at 8:18 PM

I have to confirm it looks bizarre. No key - crash, key exists - work like a charm. Tried many times, on different CPU load (to screw timing a little) but it behaves the same all the time.
Released 1.1.0.2 (no nuget package yet! - go to download page). Let me know if it helped.

Krashan wrote Apr 23, 2014 at 8:19 PM

Oh, and I have to add that my applications i use it with worked 10/10 whenever key existed or not.

DavidZidar wrote Apr 23, 2014 at 8:33 PM

Yeah, I wasn't able to reproduce this outside of my app no matter what I tried and I wasn't able to solve it in my app no matter how much code I deleted. Really, really strange stuff. As I write this I just realized it might have something to do with Microsoft.Bcl.Build and Microsoft.Bcl.Async, never tried experimenting with that.

Anyway, version 1.1.0.2 seems to work great now. Tried it on two Windows 8 machines and one Windows 7 VM. Just sent you a new build in PM.

I'll wait for the nuget package before I push this to my users.

Thank you!

DavidZidar wrote Apr 23, 2014 at 8:51 PM

No luck reproducing it with Bcl.Async either. I think I will drop it now, 1.1.0.2 works.