2

I have a go program that executes a WMI query then converts the data back into go-land data structures (using the method here). Every so often, go's GC comes along and nukes some seemingly random parts of memory to 0s, causing horrible breakage.

I am trying to figure out what exactly is causing this problem, and the next step, I believe, is to understand what happens during the COM call. My current understanding is:

  1. call into COM with the WMI query from a process
  2. the OS executes the query and writes the results into some memory location owned by the process
  3. that location is returned from the COM call, which I can then access and serialize

Is this about what happens? How does Windows choose that memory location such that it doesn't overwrite existing data?

Community
  • 1
  • 1
mjibson
  • 16,852
  • 8
  • 31
  • 42
  • COM objects are usually allocated on the heap. After that they are reference counted. The location is chosen by the normal runtime heap. – Lou Franco Feb 27 '14 at 03:02
  • Normally your objects will not be GC'd (and so overwritten) until they are no longer referenced by the code. There's some reference counting problem in there. – sharptooth Feb 27 '14 at 07:51
  • This now appears to be a problem with Go not keeping around pointers to objects returned from COM, as some of you have suggested. I've updated the github issue with the latest research: https://github.com/mattn/go-ole/issues/13#issuecomment-36314577 – mjibson Feb 28 '14 at 01:58

1 Answers1

1

Every COM object is reference counted with AddRef() and Release(). Perhaps you need an extra AddRef() to keep it around longer.

I see from the sample code that there are a lot of defered Release calls. This is fine because we want the objects released at the end of main. In your program you might want to put off Release even longer (but, I don't know go or exactly what defer does)

Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • I will test the ref counting to see if it's the problem. I'm skeptical that it is the reason, though, because if I disable the go GC (or compile and run as a 32-bit go app) then everything works correctly. – mjibson Feb 27 '14 at 03:20
  • Do go objects have references to COM objects that they release on GC? If so (1) perhaps the go object needs something to reference it to keep it around -- for example if a COM object is the only thing referencing a go object, the go GC might not know about it. (2) perhaps there is still an extra AddRef needed and the GC'd object is not supposed to be the last Release. – Lou Franco Feb 27 '14 at 12:36
  • Ref counting does not appear to be the problem. After removing the Release calls and then adding AddRef calls the problem remains unchanged. – mjibson Feb 27 '14 at 21:01
  • Next thing to look at is thread models. Does WMI need a single threaded COM apartment STA vs MTA? If so, you need to start a thread, make it STA and do all WMI access from there. – Lou Franco Feb 28 '14 at 01:08
  • I was already doing that (https://github.com/StackExchange/wmi/blob/085b191bad15e6b5fd16365b81541f8e0a9d6cb0/wmi.go#L39). A go routine locked itself to a thread, init'd COM, and then sent all WMI queries through that thread. Check my new comment on the question for some progress. This is looking like there are no references to the COM data, so they get GCd, but are being used still. – mjibson Feb 28 '14 at 02:02