REVCLOUD command crashes AutoCAD

REVCLOUD command crashes AutoCAD

Antti_Karanta_
Participant Participant
742 Views
13 Replies
Message 1 of 14

REVCLOUD command crashes AutoCAD

Antti_Karanta_
Participant
Participant

I am investigating an access violation that crashes AutoCAD when issuing REVCLOUD command in a drawing where our C# plugin is listening to command and object add/modify/remove events. The crash occurs immediately after I press enter after having typed the command.


The code executed by our listener callbacks just before the crash does not seem to do much anything, certainly nothing suspicious, and most of it unrelated to AutoCAD API (e.g. logging the event). Of course there is plenty of things that have been done before that point, i.e. before the REVCLOUD command is issued.

 

The crash does not occur on AutoCAD 2020 or older, but does for at least AutoCAD 2021 and AutoCAD 2024.
I am suspecting there is something our code does wrong along the way (e.g. failing to Dispose something that needs to be disposed) but it only manifests later and only with newer AutoCAD versions.

 

The crash is very reproducible, i.e. happens every time when using REVCLOUD in a drawing where the event listeners are active. However, in the same AutoCAD process for a drawing without the event listeners the REVCLOUD command works fine.


Here's the stack trace at the time of the crash, obtained using WinDBG:

 

[0x0] acdb24!AcDbDatabase::tilemode 0x5dfe7ff188 0x7ffdbb41a0b2
[0x1] acrevcloud+0xa0b2 0x5dfe7ff190 0x7ffdbb419518
[0x2] acrevcloud+0x9518 0x5dfe7ff2c0 0x7ffdbb41965a
[0x3] acrevcloud+0x965a 0x5dfe7ff320 0x7ffdbb41f0a8
[0x4] acrevcloud+0xf0a8 0x5dfe7ff3c0 0x7ffcedcbb889
[0x5] accore!AcApDocImpManager::unlockCurDocument+0xb75 0x5dfe7ff6f0 0x7ffcedcb990e
[0x6] accore!acedInitCommandVersion+0x562 0x5dfe7ff7c0 0x7ffcedcb9636
[0x7] accore!acedInitCommandVersion+0x28a 0x5dfe7ff870 0x7ffcedcafaf1
[0x8] accore!AcApAppImp::GetSDIMode+0xab5 0x5dfe7ff8e0 0x7ffcedd07050
[0x9] accore!CCmdThroat::Run+0x118 0x5dfe7ffc70 0x7ffcedd07cba
[0xa] accore!AcApAppImp::run+0x52 0x5dfe7ffd10 0x7ffcedd07c79
[0xb] accore!AcApAppImp::run+0x11 0x5dfe7ffd40 0x7ff615a4ac65
[0xc] acad!AcMenuIconLibrary::CommandCache+0x669d 0x5dfe7ffd70 0x7ffe52cf2bf0
[0xd] mfc140u!AfxWinMain+0xc0 0x5dfe7ffde0 0x7ff615a9b73e
[0xe] acad!AcLineThumbnail::operator=+0xb45e 0x5dfe7ffe20 0x7ffe7ce0e8d7
[0xf] KERNEL32!BaseThreadInitThunk+0x17 0x5dfe7ffe60 0x7ffe7df514fc
[0x10] ntdll!RtlUserThreadStart+0x2c 0x5dfe7ffe90 0x0

 

Any ideas on how to investigate this problem are greatly appreciated.

0 Likes
743 Views
13 Replies
Replies (13)
Message 2 of 14

kerry_w_brown
Advisor
Advisor

Can we assume you aren't using AC2025+ IE NOT USING .NET8.0+

 

Without seeing the functioning code associated with trapping and handling the events, I doubt anyone could determine the cause of your crash ( with certainty )

 

Regards,


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 3 of 14

ActivistInvestor
Mentor
Mentor

I don't think anyone here is going to be able to guess what the problem might be with your event handling code so if you do not want to disclose it there is nothing anyone can do for you. 

0 Likes
Message 4 of 14

Antti_Karanta_
Participant
Participant

Hi Kerry and ActivistInvestor

 

Thanks for your replies. 

 

We have not ported this particular plugin yet to .net 8. Currently supporting AutoCAD 2021..2024 and using .NET 4.8 on Windows 11

 

I can share the code executed in the event handlers prior to the crash. I doubt there is much to learn here, that's why I did not include it originally.

 

There are two separate Document.CommandWillStart listeners executed. 

 

The first one (and absolutely all the code it calls) is as follows: (I've added comments to clarify e.g. which branch in conditionals we take):

 

 

void Document_CommandWillStart( object sender, CommandEventArgs e ) {
	if ( IsOpenOrQuitCommand( e ) ) return;
	// g_Logging == false in this case
	if ( g_Logging ) g_logger.LogCommandEvent( e, "CommandWillStart", UnLoggedCommands, _commandStack );
	StartCommand( e.GlobalCommandName );
}

private static bool IsOpenOrQuitCommand( CommandEventArgs e ) {
	return e.GlobalCommandName == "OPEN" || e.GlobalCommandName == "QUIT" || e.GlobalCommandName == "NSQUIT";
}

private readonly Stack<string> _commandStack = new Stack<string>(); // from System.Collections.Generic
private bool IsCommandActive => _commandStack.Count > 0;
internal static readonly HashSet<string> IgnoredCommands = new HashSet<string>( ... list of ignored command names, HashSet from System.Collections.Generic


void StartCommand( string commandName ) {
	if ( !IsCommandActive && !IsRefEditActive() && !IgnoredCommands.Contains(commandName) )
		InitializeCommandChangeSet();
	_commandStack.Push( commandName );
	// EventHandlingActive is true in this case
	if ( EventHandlingActive ) {
		_unsupportedTypesDuringCommand = new HashSet<string>();
	}
}

private bool EventHandlingActive => _eventHandlingActive && _silentActionCount == 0; // bool and in fields, respectively

public static bool IsRefEditActive() {
	var refEditActive =  ( (string)AcadApplication.GetSystemVariable( "REFEDITNAME" ) != "" );
	return refEditActive;
}

private void InitializeCommandChangeSet() {
	_changeSetDuringCommand = new ChangeSet();
}

public ChangeSet( ChangeSet copyCommandInformationFrom = null ) {
	_appended = new HashSet<Tuple<int, ObjectId>>( OBJECTID_COMPARER );
	_erased = new HashSet<ObjectId>();
	_modified = new HashSet<ObjectId>();
	// in this case, copyCommandInformationFrom == null
	if (copyCommandInformationFrom == null) {
		_commandsUsedOnObject = new Dictionary<ObjectId, IList<string>>(); // from System.Collections.Generic
	} else {
		_commandsUsedOnObject = copyCommandInformationFrom._commandsUsedOnObject;
	}
}

 

Then a separate event handler is executed

 

private void Document_CommandWillStart(object sender, CommandEventArgs e) {
	if (!IsLogging || IsIgnoredCommand( e ) ) return; // in this case the condition is false and we do proceed to invoke a method on the logger object

	g_logger.Debug($"[{ProcessId}] command: {e.GlobalCommandName}"); // g_logger is NLog.Logger, NLog version 4.7.15
}


public bool IsLogging {
	get { return _isLogging; }
	// setter here also, but it is not invoked during this command event so not shown now
}

private static bool IsIgnoredCommand(CommandEventArgs e) {
	return ModificationTracker.IgnoredCommands.Contains( e.GlobalCommandName ); // this is the same IgnoredCommands HashSet<string> shown above
}

private static readonly int ProcessId = Process.GetCurrentProcess().Id;

 

It's all managed code and fairly simple at that.

 

Before the REVCLOUD command has been given, thousands of lines of code has been executed and my suspicion is that the problem is somewhere there.

 

I was not expecting anyone could easily point to the exact problem. What I was hoping for was to hear e.g. if there someone had had similar problems with REVCLOUD or if there was some common pattern (e.g. not Dispose():ing a certain type of AutoCAD object) that resulted in REVCLOUD crashing, or anything that might give me any ideas on how to narrow down on how to look for the root cause.

0 Likes
Message 5 of 14

ActivistInvestor
Mentor
Mentor

Your code (and specifically the event handlers) have no exception handlers. Exception handling is not optional in handlers of Document and Database events, because when an exception is thrown by an event handler, if it doesn't crash AutoCAD, it will disable all event handlers, and the events will no-longer fire.

 

I'm surprised you haven't already taken this first step: Wrap all of the code in the event handlers in a try{...} block, followed by a catch{} block that displays the exception on the console.

void Document_CommandWillStart( object sender, CommandEventArgs e ) 
{
   try
   {
      // all of the original code from this method should go here:
      if ( IsOpenOrQuitCommand( e ) ) return;
      if ( g_Logging ) g_logger.LogCommandEvent( e, "CommandWillStart", UnLoggedCommands, _commandStack );
      StartCommand( e.GlobalCommandName );
   }
   catch(System.Exception ex)
   {
      ((Document) sender).Editor.WriteMessage(ex.ToString());
   }
}
0 Likes
Message 6 of 14

kerry_w_brown
Advisor
Advisor

@Antti_Karanta_ 

Perhaps you could create a (working or failing) solution that contains only the bare bones necessary to show the code used.
Something you can actually debug.

Something that you can share, without the need for people to code their own Solutions to create an assembly.

Something to demonstrate how you are using the app . . . Command Switches , Document mode, etc.

Does Autocad crash on the command when called from both from the menu and command line ??

Is the command called (to trigger the event) a pure AutoCAD command ?

Does it crash on this command only ?
Does it crash on this command in multiple drawings ?

 

Did the code crash AutoCad 2021 and 2024 the first time you tried it , or after some changes to the version that ran in 2020?

 

Are the 2021 and 2024  version Assemblies built explicitly against their relevant SDK librarys ?

 

Regards,

 

 

 

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 7 of 14

Antti_Karanta_
Participant
Participant

Hi Kerry,

Extracting a minimal reproducer is quite difficult. As I said, there is quite a lot of code executed as this plugin opens the drawing and creates a whole bunch of objects before the user gets to do anything. If I had any idea which part of the code might be the culprit that would already be a huge leap forward, but I don't.

 

As for the other details you asked about:

 

We are using MDI mode

 

The crash occurs by typing "REVCLOUD" and pressing enter. I had not tried creating a revcloud using the ribbon drawing tools, thanks for that idea. And it turned out that works - no crash.

 

REVCLOUD is the only command that crashes AutoCAD. There is a report of a crash occurring occasionally when opening the drawing (and like I said, there is lots happening there), but that does not reproduce very often. I have not been able to reproduce it myself at all. However, REVCLOUD command crash happens every time.

 

The REVCLOUD command crashes AutoCAD on every drawing where our plugin is enabled. The command works in other drawings, even if they are in the same AutoCAD process.

 

The same exact plugin code (same binary) run in AutoCAD <= 2020 does not reproduce the crash.


According to this, Autodesk made changes to REVCLOUD in AutoCAD 2021: https://www.scan2cad.com/blog/cad/autocad-revision-cloud/ . That sounds relevant.

 

The plugin is built against AutoCAD-2017.Net.Base https://www.nuget.org/packages/AutoCAD-2017.Net.Base
I tried updating to AutoCAD-2021.Net.Base but the crash still occurs, both on AutoCAD 2021 and AutoCAD 2024.

 

 

        .::Antti::.

0 Likes
Message 8 of 14

Antti_Karanta_
Participant
Participant

Hi ActivistInvestor,

 

Thanks for the tip, that would be a good idea.

 

In this particular case I am certain there are no exceptions as I stepped through our code step by step with a debugger. The crash occurs deep in AutoCAD way after our code has been executed (please see the stack trace in the original post).

 

 

          .::Antti::.          

0 Likes
Message 9 of 14

Antti_Karanta_
Participant
Participant

I now tried creating a revcloud from the ribbon again and now it crashes every time. The one time it worked was some kind of lucky exception to the rule.

0 Likes
Message 10 of 14

ActivistInvestor
Mentor
Mentor

Whether you're sure there are no exceptions in your code or not, you should still use try/catch unconditionally. At some point, you may make revisions that might cause an obscure bug to throw an exception. Sound coding would be prepared to deal with that eventuality, rather than allow it to crash AutoCAD.

 

In your OP you said:

I am investigating an access violation that crashes AutoCAD when issuing REVCLOUD command in a drawing where our C# plugin is listening to command and object add/modify/remove events.

What 'add/modify/remove' events?  I don't recall seeing any handlers for those events, and they are the most-likely suspects and the most-common cause of exception-induced crashes.

 

Message 11 of 14

Antti_Karanta_
Participant
Participant

Hi ActivistInvestor,

 

I was not arguing against adding exception handlers to the event listener code. What I was trying to say is that in this particular instance, i.e. the crash produced by REVCLOUD command, no exception occurs. This I know because I stepped through the invoked event handler code step by step, and there were no exceptions. The crash then occurs after the control returns to AutoCAD.

 

As for the other event handlers, I did not post their code as they do not get executed in this case. I.e. what happens after issuing the REVCLOUD command is that the above posted Document_CommandWillStart event handler is triggered. It is executed without exceptions being thrown. Then the control returns to AutoCAD. No other event handlers are triggered (I have checked this by having breakpoints in them).

To put it another way, all the plugin code that gets executed between issuing the REVCLOUD command and the crash is posted above. 

0 Likes
Message 12 of 14

ActivistInvestor
Mentor
Mentor

@Antti_Karanta_ wrote:

Hi ActivistInvestor,

 

As for the other event handlers, I did not post their code as they do not get executed in this case. I.e. what happens after issuing the REVCLOUD command is that the above posted Document_CommandWillStart event handler is triggered. It is executed without exceptions being thrown. Then the control returns to AutoCAD. No other event handlers are triggered (I have checked this by having breakpoints in them).

To put it another way, all the plugin code that gets executed between issuing the REVCLOUD command and the crash is posted above. 


The question isn't whether the event handlers you didn't post execute after issuing REVCLOUD and before the crash.

 

The question is whether those event handlers executed at any point prior to that, because an event handler can do things that may not manifest immediately as a crash. They can do things that can cause any subsequent operation to fail (depending on what the operation does), even if they aren't called after that operation starts.

 

So, any event handler that executes prior to starting REVCLOUD is relevant.

0 Likes
Message 13 of 14

Antti_Karanta_
Participant
Participant

Hi ActivistInvestor,

 

Thanks for being interested in my problem and trying to help.

 

As the code executed between issuing the REVCLOUD command and the crash seems very unlikely to cause the crash, you are right in that the root of the problem must be in some code executed before that. Unfortunately that is not just the other event handlers.

 

Like I stated in my reply 05-18-2025 there's thousands of lines of code executed before we get to this point. Due to the nature of the plugin, the code is executed when opening the drawing. This makes it very difficult to extract a minimal reproducible sample (I have tried and am still experimenting with that).

 

Even initially when making my post I was fairly certain the problem is not in the code executed between giving the command and the crash. My best hope was that someone might e.g. have an insight into a typical cause for this kind of crash so I would know better what to look for. Or some methodology on how to investigate, e.g. if there was possibly some debugging mechanism in AutoCAD to help a programmer detect if an object that should be Disposed in the AutoCAD main thread ends up being Disposed by the garbage collector thread. Or whatever it might be.

 

 

         .::Antti::.

0 Likes
Message 14 of 14

ActivistInvestor
Mentor
Mentor

A common cause for delayed crashes is opening objects and not closing or disposing them.

0 Likes