How can I find all objects of a particular type?


More than one customer has asked a question like this:

I'm looking for a way to search for all instances of a particular type at runtime. My goal is to invoke a particular method on each of those instances. Note that I did not create these object myself or have any other access to them. Is this possible?

Imagine what the world would be like if it were possible.

For starters, just imagine the fun you could have if you could call typeof(Secure­String).Get­Instances(). Vegas road trip!

More generally, it breaks the semantics of App­Domain boundaries, since grabbing all instances of a type lets you get objects from another App­Domain, which fundamentally violates the point of App­Domains. (Okay, you could repair this by saying that the Get­Instances method only returns objects from the current App­Domain.)

This imaginary Get­Instances method might return objects which are awaiting finalization, which violates one of the fundamental assumptions of a finalizer, namely that there are no references to the object: If there were, then it wouldn't be finalized! (Okay, you could repair this by saying that the Get­Instances method does not return objects which are awaiting finalization.)

On top of that, you break the syncRoot pattern.

class Sample {
 private object syncRoot = new object();
 public void Method() {
  lock(syncRoot) { ... };
 }
}

If it were possible to get all objects of a particular class, then anybody could just reach in and grab your private sync­Root and call Monitor.Enter() on it. Congratuations, the private synchronization object you created is now a public one that anybody can screw with, defeating the whole purpose of having a private syncRoot. You can no longer reason about your syncRoot because you are no longer in full control of it. (Yes, this can already be done with reflection, but at least when reflecting, you know that you're grabbing somebody's private field called sync­Root, so you already recognize that you're doing something dubious. Whereas with Get­Instances, you don't know what each of the returned objects is being used for. Heck, you don't even know if it's being used! It might just be garbage lying around waiting to be collected.)

More generally, code is often written on the expectation that an object that you never give out a reference to is not accessible to others. Consider the following code fragment:

using (StreamWriter sr = new StreamWriter(fileName)) {
 sr.WriteLine("Hello");
}

If it were possible to get all objects of a particular class, you may find that your customers report that they are getting an Object­Disposed­Exception on the call to Write­Line. How is that possible? The disposal doesn't happen until the close-brace, right? Is there a bug in the CLR where it's disposing an object too soon?

Nope, what happened is that some other thread did exactly what the customer was asking for a way to do: It grabbed all existing Stream­Writer instances and invoked Stream­Writer.Close on them. It did this immediately after you constructed the Stream­Writer and before you did your sr.Write­Line(). Result: When your sr.Write­Line() executes, it finds that the stream was already closed, and therefore the write fails.

More generally, consider the graffiti you could inject into all output files by doing

foreach (StreamWriter sr in typeof(StreamWriter).GetInstances()) {
 sr.Write("Kilroy was here!");
}

or even crazier

foreach (StringBuilder rb in typeof(StringBuilder).GetInstances()) {
 sb.Insert(0, "DROP TABLE users; --");
}

Now no String­Builder is safe—the contents of any String­Builder can be corrupted at any time!

If you could obtain all instances of a type, the fundamental logic behind computer programming breaks down. It effectively becomes impossible to reason about code because anything could happen to your objects at any time.

If you need to be able to get all instances of a class, you need to add that functionality to the class itself. (GC­Handle or Weak­Reference will come in handy here.) Of course, if you do this, then you clearly opted into the "anything can happen to your object at any time outside your control" model and presumably your code operates accordingly. You made your bed; now you get to lie in it.

(And I haven't even touched on thread safety.)

Bonus reading: Questionable value of SyncRoot on Collections.

Comments (28)
  1. Gordon says:

    foreach (StringBuilder rb in typeof(StringBuilder).GetInstances()) {

    sb.Insert(0, "DROP TABLE users; –");

    }

    Oh yes, the famed "Bobby Tables" attack: http://xkcd.com/327/

  2. Dan Bugglin says:

    The answer that is closest to what the customer wants:

    Use reflection to grab the objects you are looking for, assuming you know where you want to look already and it's just a matter of not having access (ie private).

    The sane answer:

    Request the author make changes to expose the functionality you require.  If it's open source code, even better; make the change yourself.

  3. Peter says:

    Nice article, Raymond, but I'd like to know more about exactly what the customers are trying to accomplish.  I presume that they don't want to inject graffiti into random files or to run around locking private objects willy nilly.

  4. Gabe says:

    Given that C# allows pointers in certain scenarios (unsafe/full-trust), there's no reason you couldn't write your own lame brute-force implementation of this. Giving us a proper implementation would merely prevent us from having to do it ourselves (poorly). Of course you would never want to write application logic that relies on such a feature, but having used similar features in Python, it's easy to see where it would be useful for unit tests, diagnostics, or benchmarking.

  5. Cheetah says:

    This sounds like part of what memory leak debuggers / tracers do (minus the calling methods part).  If one combined the memory debugger with some features from a "normal" debugger, one could do this.

    Of course, always running an app under such a tool will have some pretty heinous performance implications, and the problem statement definitely reeks of deserving a "don't do that" response.

  6. Paul Betts says:

    In Ruby, this is absolutely possible via ObjectSpace#each_object. Yes, I think it's crazy too.

  7. Your SQL injection string is missing a ');

  8. Somebody says:

    It doesn't need one because it's being inserted at the beginning of the string, not into an SQL literal string.

  9. Vilx- says:

    I now eagerly expect rants to start appearing in the internet about Raymond posting non-working code in his blog with APIs that don't exist.

  10. Mike Dimmick says:

    Gabe, Cheetah: that's what the CLR Profiling API is for. It's acceptable that something looking in from outside can see things that aren't exposed inside the sandbox.

  11. Manu says:

    Like Cheetah, I'd say this is useful to have when debugging situation where the garbage collection should be able to collect some objects but for some reasons this is not happening.

  12. Mmmh says:

    I agree that such a feature would be of dubious utility, would have a performance impact and needs much more thinking, and I especially agree that this is more a signal that the customer is searching for the answer of the wrong part of the question. A bad idea in general.

    However, I find the examples you brought to the table quite preposterous (I hope it's the right term, I'm italian :)).

    In the end is code operating on the same AppDomain (and process space) of the application.. is your code. Yes, it would be a nice way to shoot yourself on the foot but there are plenty ways of doing that. You could Invoke on the main form to have it waiting forever on a ad-hoc mutex. Or you could launch a format of the hard drive. Or you can drop tables without the need of being malicious and going to find StringBuilders.

    The point is, I think, the big violation of OOP principles, not much security issues.

    And now of course the ranting part :)

    I think having "every object is a monitor" as a very bad choice (for performance, complexity, design cleanliness, etc.); a proper Monitor object would have been much much better. Now of course if MS only had a time machine.. (and Sun too).

  13. Peter says:

    @Mmmh: I seem to recall Joe Duffy making a comment along the lines that monitors seemed like a good idea at the time.  Anyway, hindsight is always 20/20.

  14. CPDaniel says:

    @Mmmh:  ISTR that "evert object IsA monitor is not true".  "Every object can act like a Monitor if someone asks it to" is more accurate.  Under the covers, the CLR doesn't allocate any of the Monitor machinery for an object unless code tries to use it in a synchronization operation.

  15. Leonel says:

    Imagine a world where all the fields are public and all the methods virtual! The madness, the chaos!

    steve-yegge.blogspot.com/…/wikileaks-to-leak-5000-open-source-java.html

  16. tobi says:

    I believe that this would indeed be a very useful debugging tool in full trust. Alas the potential for misuse is extreme.

  17. Joshua says:

    I actually do this (find all objects of a given type).

    I do so when hunting for memory leaks.

    The code required to do so is in sos.dll.

    Oh, and this is one time where GC.Collect() is useful as the lie about infinite memory causes real problems when hunting managed memory leaks.

  18. Miral says:

    @Joshua:

    I do the same thing, but that doesn't really count as "at runtime".  It's more "post mortem". :)

  19. mirobin says:

    If they wanted to be particularly evil, they could probably use the .Net profiling API to accomplish this…  but it'd still be a bad idea.  :)

  20. Mmmh says:

    @CPDaniel  

    I find at which time they will be detected to be interesting: at compile-time most uses are undetectable (but the syncroot is detectable already here), at jit-time most are detectable but some can only be detected at run-time (for example if loading an assembly manually). I hope they use multiple methods to avoid unnecessary overhead at runtime. I'll try to find some info about.

    @Peter

    Most of the CLR design "recalls" (so to speak :)) Java design – with plenty of corrections where Java, in the years, demonstrated having taken a bad choice.

    The similarities are struggling from the macro level (Object as a root of all hierarchies, interfaces vs abstract classes, String is immutable, etc.) and the differences are exactly in a thousand of those "tiny" details that made generations of Java programmers screaming (automatic boxing, enums, operators overloading, etc.). I guess in the case of "every-object-could-be-a-monitor" this inspiration lead a bit too far – probably because Java programmers were not complaining about that point.

    @Blog software owners – I know it's not Raymond ;)

    The Post button seems to be more of "Take-a-random-action-one-of-which-is-Post" :) Most of the times it does not seem to work (Firefox) and simply makes me going to the top of the page.

  21. Joe says:

    Stunningly bad idea.

    foreach(IDisposable obj in typeof(IDisposable ).Get­Instances())

    {

     obj.Dispose();

    }

  22. Omer Raviv says:

    Here's an example of how to do this, from Sasha Goldstein's blog:

    blogs.microsoft.co.il/…/gc-helper-for-obtaining-live-instances-of-a-type-or-how-i-implemented-gc-getaliveinstancesof-lt-t-gt.aspx

    I definitely agree that using this outside of debugging/profiling scenarios is a very bad idea.

    [This falls into the "you need to add that functionality to the class itself" category, since that's what happened. -Raymond]
  23. Richard Cox says:

    If you are outside the process with the right permissions (either Windows Debug privilege or process owner) you can do this with WinDBG and SOS: !dumpheap -type <name>.

    This is of course violating the "from inside the .NET process" requirement.

  24. Joshua says:

    @Richard:

    Nobody said a full trust .NET application can't spawn child processes. For instnace, spawning a native bzip2.exe in pipe is four times faster than using the ICSharp library (I measured it). Therefore I do that.

  25. Jules says:

    @Mmmh: "The point is, I think, the big violation of OOP principles, not much security issues."

    In some situations the two are indistinguishable.  A lot of recent developments in both sandboxing and operating system design theory rely on language access rules to enforce security principles.  

    For example, we can set up a sandbox around a user-provided module, preventing it accessing any objects that it can use to damage the environment, but if it can interfere with the objects owned by the API layer between it and the sandbox then it can quite possibly trick the sandbox into granting it more access than it should.

  26. Clovis says:

    Can we also have typeof(Secure­String).Get­Instances(URL url) to look these up on other machines too?

  27. Mmmh says:

    @Jules

    Raymond supposed this : (Okay, you could repair this by saying that the Get­Instances method only returns objects from the current App­Domain.) before getting to talking about security issues.

  28. Andrew says:

    I agree that being able to get all instances of an object is madness, but being able to test to see if my own object can be garbage collected (held via a WeakReference) seems reasonable. Java has a function to do this called assertGC() for use in unit tests etc. Given the information above, can this StackOverflow question be answered as 'this is impossible in .NET'?

    stackoverflow.com/…/net-version-of-javas-assertgc-unit-tesing-memory-leaks

    [Florian's answer looks correct. Remember that depending on your build switches, the GC behaves differently. (For example, in Florian's example, the handler isn't nulled out, which means that you're relying on the JIT performing certain optimizations which it may not do depending on how you compiled). -Raymond]

Comments are closed.

Skip to main content