Bug 4484 - Removing a certificate from a store while in a foreach loop of that store's Certificates property results in an InvalidOperationException
Summary: Removing a certificate from a store while in a foreach loop of that store's C...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.Security ()
Version: master
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2012-04-17 16:39 UTC by David Ferguson
Modified: 2012-04-17 17:10 UTC (History)
1 user (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report for Bug 4484 on GitHub or Developer Community if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: GitHub Markdown or Developer Community HTML
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
NEW

Description David Ferguson 2012-04-17 16:39:16 UTC
While porting unit tests from Windows (which pass) for the application I'm porting, I came across this one:

        public void RemoveAllProductCertificates()
        {
            var store = GetProductCertificateStore();

            try
            {
                store.Open(OpenFlags.ReadWrite);

                foreach (var certificate in store.Certificates)
                {
                    store.Remove(certificate);
                }
            }
            finally
            {
                store.Close();
            }
        }

This is mainly used in our unit testing teardown/setup, etc.  When store.Remove is called, the exception is thrown.  Here's the callstack:

TearDown : System.InvalidOperationException : List has changed.

 at System.Collections.ArrayList+SimpleEnumerator.MoveNext () [0x00066]
 at System.Security.Cryptography.X509Certificates.X509Certificate2Enumerator.MoveNext () [0x00000]
 at MyNamespace.RemoveAllProductCertificates () [0x00061]

The Certificates property simply returns a list which can't be modified in a foreach.  The Windows api simply wraps other api's so there isn't an internal collection being modified when calling .Remove in the foreach.

Steps to reproduce:

1) Run the above code in a test (backup your store first!)

Expected results:

The code should behave as it does in Windows

Actual results:

A System.InvalidOperationException is thrown

System details:

Mono JIT compiler version 2.11.1 (master/ec75771 Wed Apr 11 14:13:09 EDT 2012)
Copyright (C) 2002-2012 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug 
        LLVM:          supported, not enabled.
        GC:            Included Boehm (with typed GC and Parallel Mark)
Comment 1 David Ferguson 2012-04-17 17:10:19 UTC
store.RemoveRange(store.Certificates) will also throw the exception.

The code below works fine.

            try
            {
                store.Open(OpenFlags.ReadWrite);

                var certs = new X509Certificate2Collection(store.Certificates);
                store.RemoveRange(certs);
            }
            finally
            {
                store.Close();
            }