Rare exception when loading MSCoreLib

SyntaxEditor .NET Languages Add-on for Windows Forms Forum

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Version: 12.1.0288
Platform: Universal Windows Controls
Environment: Windows 7 (64-bit)
Avatar

Hi,

I recently got a bug report where an exception was thrown while loading the MSCorLib into the AssemblyCodeRepository.
The content seems to be already in the cache, but there is an IOException when accessing the file, saying the file is locked by a different application.
I was not able to reproduce the issue, so I am asking you, what possible reasons you could imagine.

The complete process is running in a separate thread, so multiple resolver instances could try to access the file simultaneously. I already tried that by making multiple threads in a loop, but it worked.

The cache path is the default path, so it's in the users temp directory. Since we are stuck on the 288 release, I checked if a newer release could have fixed the issue, but I didn't find anything similiar in the changelog.

Sorry that I cannot give you more information since I cannot reproduce the issue, but maybe you remember a similiar case or have an idea based on your background knowledge.


Best regards, Tobias Lingemann.

Comments (12)

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

We haven't had any reports of that.  I believe all our cache file loading code has FileShare.Read passed, even in your build, so it should allow multiple files to read it at the same time.  Now writing the cache file does put a lock on the file while it's being written but that should occur pretty fast and then be done.  I'm not sure what it could be other than a timing issue with read/write being performed at the same time from different app instances.


Actipro Software Support

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Yeah, but I think it is odd that it's the MsCorLib. We are generating several assemblies during runtime, so the cache is updated for those assemblies. But the MsCorLib is never changed, why would the cache write to that file?

Using multiple app instances is not an unusual use case. It would be a pitty if the assembly cache is not locked correctly. Even if it is an "one in a million" case.


Best regards, Tobias Lingemann.

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

I agree, it shouldn't be getting written to other than the first time.  Do you have a stack trace and other exception info you can post of where it's getting locked up?  But like I said, I think we already do have FileShare.Read active on all file opens.


Actipro Software Support

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

I only have a screenshot of the stack trace, but I cannot upload any images here.

Basically it's an AggregateException because it was thrown in a background thread. The inner exception is an IOException, saying the process cannot access the file, because it is locked. The file name is "D:\TEMP\SyntaxEditorDotNetProjectResolverCache\mscorlib.9de7d185.Reflection.dat".

The exception was thrown at AssemblyProjectContet.SaveToCache(DateTime dateTime, String path) in line 1265. The code of the line is the following:

using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None)) {


Best regards, Tobias Lingemann.

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

The SaveToCache method doesn't get called it if was properly reloaded from existing cache data.  So for some reason on your end, the MsCorLib cache data isn't valid for the assembly you are loading.

When I run our demo several times in a row here, it is pulling the same one successfully.

I wonder if it has something to do with your use of the default temp path instead of giving it an explicit path for cache files?


Actipro Software Support

Answer - Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Okay, I would guess this is probably what happend:

1) The cache is invalid for whatever reason.

2) The app starts and loads multiple files that need different resolver instances.

3) The resolver are initialized simultaneous in different threads.

4) While the first instance is updating the cache, the second instance fails to write the file.

I am not sure what the path could have to do with that. The temp path is usally a good choice because all users have write access to it. A lot of companies are very restrictive in terms of file rights. Most don't even grant their employees admin user rights and a lot of files are stored on a network drive.

I have to admit that I am still not able to reproduce the issue, but the assembly cache should be locked correctly anyway. I will modify the source code for our project in the hope, that this will fix the issue.


Best regards, Tobias Lingemann.

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Okay, I was able to reproduce the issue now. I have to delete the cache files in order to force the update. Two instances of the resolver in different threads and I get the exception.

This is not even an unrealistic use case. Our projects must be transferable from one PC to another. Often people that write the code are not the ones that execute it.


Best regards, Tobias Lingemann.

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Oh one more thing. Will future versions be more thread safe? Or are you waiting for the next major release, which will be based on the WPF structure? I assume the WPF version will already have better support for threads.


Best regards, Tobias Lingemann.

Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

While we don't like to catch exceptions in the component libraries (because then it can mask other issues), in this case we don't want the whole app to die or a project content to not load properly so we should add some handling.

Can you put together a new simple sample project that shows this crash so that we can use it to debug with and ensure what we change fixes your problem?  E-mail it to our support address and reference this post.  Rename the .zip file extension so it doesn't get spam blocked.  Thanks!

In regards to thread safety, even if we made this code thread-safe, that won't help with multiple app instances (which it seems like you have?).  Since when you have multiple apps running, those threads are in separate processes and locking one won't affect the others.


Actipro Software Support

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

Actually my case was just one app instance with multiple threads. In theory the problem still exists with mutliple app instances, but I think this would only apply for those libraries I create during runtime (and are used in both app instances). That would be a different topic and must be handled within my application.

Since the whole update and generation process takes some time too and I have to write the file to the filesystem, before the assembly cache can even be updated, I am not even sure this will ever happen. Upating the cache is usally very fast and it really has to happen simultaneously. It might as well crash while I generate the assembly. So we would need a different approach here anyway.

To reproduce the issue just clear the cache and run this code:

var tasks = new List<System.Threading.Tasks.Task>();

for (int i = 0; i < 2; i++)
{
  var t = new System.Threading.Tasks.Task(() =>
  {
    var resolver = new DotNetProjectResolver();
    resolver.AddExternalReferenceForMSCorLib();
  });

  tasks.Add(t);
}

foreach (var item in tasks)
{
  item.Start();
}

[Modified 6 years ago]


Best regards, Tobias Lingemann.

Answer - Posted 6 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Tobias,

I tried running that code and nothing blew up for me.

I've added additional code to AssemblyCodeRepository to lock on a thread sync object whenever assembly project content is being loaded.  Hopefully this change for the next maintenance release will help solve the problem for you.


Actipro Software Support

Posted 6 years ago by Tobias Lingemann - Software Devolpment Engineer, Vector Informatik GmbH
Avatar

I should have mentioned that you need to run the code in release mode with no debugger attached. And as I said, clear the cache on the file system, so that both resolvers try to write the file on the file system.

But thanks anyway. I am looking forward for the next release.


Best regards, Tobias Lingemann.

The latest build of this product (v2018.1 build 0341) was released 3 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.