[RhinoCommon] Occasional IndexOutOfRangeException on UserDictionary access when creating many meshes

Let me start by saying that I have no surefire way to reproduce this. But maybe it is useful anyway.

I had a piece of code that created a Mesh object and put values in its UserDictionary in the DrawForeground method of a DisplayConduit. To the credit of Rhino this did not noticably delay redrawing, even though a Mesh object with up to several thousand faces was created at every redraw frame. Recently (maybe with the introduction of SR7, I’m not sure) this started to behave erratically. Crashes would ensue, giving us no clear way to know what was going on.

Then, today I got a clear exception report saying the following

IndexOutOfRangeException

with stacktrace (the piece inside RhinoCommon is reproduced)

   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Rhino.DocObjects.Custom.UserData.StoreInRuntimeList(UserData ud)
   at Rhino.DocObjects.Custom.UserDataList.Add(UserData userdata)
   at Rhino.Runtime.CommonObject.get_UserDictionary()

I haven’t been able to reproduce this again unfortunately.

I have adapted my DrawForeground code though, that is uses a cached Mesh representation rather than create a mesh at each frame redraw.

Hello,

I ran into a similar issue when trying to assign data to the user dictionaries of object attributes.
It appears that on some (random?) occasions, the attributes’ userDictionary is not initialized correctly upon creation and the IndexoutOfRangeException is thrown.
Here’s a screenshot of the error I get upon debugging. Rhino then crashes altogether.

Does anyone know what could cause this exception? What am I doing wrong? Or a workaround to safely initialize/assign data to userDictionaries?

Many thanks,

Daniel

P.S. Here’s the simple code to reproduce this. On my computer (Rhino 5 64-bit, SR 12), the code fails after a seemingly random number of iterations. Sometimes is doesn’t.
I’ve also tried avoiding the .ReplaceContentsWith() function, but the error persists.

public class SBPRCommand2 : Command
{
public SBPRCommand2()
{
// Rhino only creates one instance of each command class defined in a
// plug-in, so it is safe to store a refence in a static property.
Instance = this;
}

    ///<summary>The only instance of this command.</summary>
    public static SBPRCommand2 Instance
    {
        get;
        private set;
    }

    ///<returns>The command name as it appears on the Rhino command line.</returns>
    public override string EnglishName
    {
        get { return "SBPRCommand2"; }
    }

    protected override Result RunCommand(RhinoDoc doc, RunMode mode)
    {

        Rhino.Collections.ArchivableDictionary arch = new Rhino.Collections.ArchivableDictionary();
        arch.Set("key1", "value1");
        arch.Set("key2", "value2");

        for (int i = 0; i < 100000; i++)
        {
            Rhino.DocObjects.ObjectAttributes att = new Rhino.DocObjects.ObjectAttributes();
            att.LayerIndex = 1;
            att.UserDictionary.ReplaceContentsWith(arch);
            
            doc.Objects.AddPoint(new Point3d(0, 0, 0.01 * i), att);
        }

        return Result.Success;
    }
}

edit:

the error also happens even with the simpler code:

            Rhino.DocObjects.ObjectAttributes att = new Rhino.DocObjects.ObjectAttributes();
            att.UserDictionary.Clear();

For some reason the UserDictionary sometimes remains null after att is created.

Does replacing:

Rhino.DocObjects.ObjectAttributes att = new Rhino.DocObjects.ObjectAttributes();

with

Rhino.DocObjects.ObjectAttributes att = doc.CreateDefaultAttributes();

work any better?

Hi Dale,

thanks for getting back to me this quickly.
Unfortunately, your tip hasn’t done the trick. I get the same error.
UserDictionary is still null after ObjectAtttributes initialisation.

Daniel

Looks like a bug in our dictionary code. I’ve reported this.

http://mcneel.myjetbrains.com/youtrack/issue/RH-31343

Dale, thanks! I look forward to this being fixed!

Hi Dale,

I see now the issue is marked as resolved but five months on the problem persists. It appears there hasn’t been a service release since SR 12 last August (5.12.50810.13095, 10.08.2015).
I saw the release target on the bug tracking site was set to a cryptic “6.0”. My question therefore: will the bug ever be fixed in Rhino 5?

Thanks!

There’s nothing cryptic about 6.0; it seems that most/all development efforts at McNeel are put into development of the next version of Rhino (v6). All bugfixes are only done for the new version. Don’t get your hopes up for a fix in 5.0.

yes, I suppose I was only hoping it was cryptic rather than the obvious…
This isn’t exactly great news. I’m developing little tools for use in our office and in their current form they will hinge on userdictionary info (and crash as described above). I’d use usertext but it’s too slow.
I don’t know for sure but I doubt we’ll be throwing out all our Rhino 5.0 licenses the instant 6.0 ships so some catering for legacy versions might be very useful indeed.
In any case I look forward to 6.0!

Hi!
Initially, we released a plug-in for SR13 called ‘Concha’. Since we wanted to have more backwards compatibility, we downgraded to SR12. With this release I’ve got these exceptions with the UserData dictionary.

My solution is to capture this exception:

  struct UserData<USERDATA_T> where USERDATA_T :         Rhino.DocObjects.Custom.UserData
  {
    public static void Set( Rhino.DocObjects.RhinoObject obj, USERDATA_T userData )
    {
        try
        {
          obj.Attributes.UserData.Add( userData );
        }
        catch( System.IndexOutOfRangeException ex )
        {
          // Running into user-dictionary bug 'http://mcneel.myjetbrains.com/youtrack/issue/RH-31343' when adding user data"
        }
     }
    }

I believe that is pretty much the one major bug we fixed in SR13.

1 Like

Can we work around this bug in SR12 by directly calling the C+±API?

Nope; sorry.

If all the related properties/members are public then you should be able to configure the structure manually. Since I only recently started to draw these diagrams (for my own use) I don’t know how much is missing in the following diagram (not knowing even if it’s correct) but it for sure would be interesting if it would be possible directly from RhinoCommon :

// Rolf

Hi @stevebaer @dale

It seems like I’m encountering the same error.
Rhino just crashes and in the Windows event viewer log I can find the following errors:

{“UxEvent”:“Exception”,“Data”:{“UserId”:“38c37417-f43f-4279-869e-c0145a7f2f0e”,“Application”:“RhinoCommon.ExceptionReport”,“Version”:“1.0.0.0”,“Type”:“System.IndexOutOfRangeException”,“Message”:“Index was outside the bounds of the array.”,“StackTrace”:" at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)\r\n at Rhino.DocObjects.Custom.UserData.OnDuplcateUserData(Int32 serialNumber, IntPtr pNativeUserData)"}}

Assuming this I’ve added checks to deal with UserDictionary only if UserDictionary is not null:

if (cObject.UserDictionary != null)  
{
     // deal with UserDictionary
}

But it looks like this didn’t help. Rhino still crashes with the same errors.

Does anyone has any idea why the error is still present? Or can there be other reasons when this exception is thrown?

Hi Yuliya,

Are you using Rhino 5 SR13? The bug, described in this thread, has been fixed in this service release…

– Dale

Hi Dale,

Thanks for quick response
Indeed I was using Rhino 5 SR 12. I checked out for updates few times but it turned out that in order to get SR 13 I needed to select Update Frequency - Service Release Candidate.

All seems to work now :slight_smile:
Thank you!