开发者

Detecting System.setProperty method invocations

I'm facing a conundrum here.

One of the applications that I've developed is loading an incorrect implementation of the DocumentBuilderFactory class of JAXP. This behavior was later deduced to be resulting from another class in different application built by a different team/company. The said class had changed the preferred DocumentBuilderFactory class upon loading, by inclusion of a static block similar to the one below:

  static
  {
    System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "a new factory");
  }

If one goes by the Javadocs of the DocumentBuilderFactory.newInstance method, it would be quite obvious that the above code was responsible for changing the parser implementation returned to all applications, when the newInstance method is invoked.

A patch was applied, which corrected this problem, but it leads me开发者_Go百科 to ask this question - how does one determine which class is performing the System.setProperty call at runtime?

We had produced a custom build of OpenJDK with a modified System class that was responsible for nailing the culprit, for the very simple reason that we did not have access to all the sources for all the applications deployed on the server. But this was possible only due to the fact that the production environment was replicated in its entiriety. The question therefore, could also be interpreted as - how does one determine which class is performing the System.setProperty call at runtime, in a production environment?


System.setProperty is checked by a SecurityManager, if installed.

You can create your own MySecurityManager and deploy at runtime. Your own SecurityManager can log some information like the current stacktrace, when the method checkPropertyAccess is called:

public class MySecurityManager extends SecurityManager
{

    public MySecurityManager()
    {
        super();
    }

    @Override
    public void checkPropertyAccess(String key)
    {
        if ("javax.xml.parsers.DocumentBuilderFactory".equals(key))
        {
            System.err.println("checkPropertyAccess(String :" + key + "): ");
            Thread.currentThread().dumpStack(); // or anything useful for
                                                // logging the context.
            new Throwable().printStackTrace(); // whatever, or use it with
            // PrintStream/PrintWriter, or some logging framework if configured.
        }
        super.checkPropertyAccess(key);
    }

    @Override
    public void checkPermission(Permission perm)
    {
        if (perm instanceof PropertyPermission)
        {
            PropertyPermission propPerm = (PropertyPermission) perm;
            System.err.println("checkPropertyAccess(String:" + propPerm.getName() + "):");
            Thread.currentThread().dumpStack(); // or anything useful for
                                                // logging the context.
            new Throwable().printStackTrace(); // whatever, or use it with
            // PrintStream/PrintWriter, or some logging framework if configured.
        }
        super.checkPermission(perm);
    }
}


String literals are UTF8-encoded in the class file format and since there is no reason to assume that the offending invoker is using code to concatenate the property name, I would simply have unpacked all JARs from the classpath into one directory and tried a recursive grep for "javax.xml.parsers.DocumentBuilderFactory" through the class files. You would have at least found all class files containing this String as a literal and hopefully not to many false positives.

If the class name of the incorrect implementation is easier to identify, it would perhaps been more clever to search for that instead.


Just start you application in debug mode, connect to it with eclipse, set breakpoint and look what class do it in call hierarchy http://www.eclipsezone.com/eclipse/forums/t53459.html


I know 2 solutions

  1. use aspect framework (aspectJ or so)
  2. Modify System class (add logging to setProperty() method) new Throwable().printStacktrace(); will report you where the method was called from.

Now run your application with option -Xbootclasspath/p and put your version System class there.

-Xbootclasspath/p:<directories and zip/jar files separated by ;> prepend in front of bootstrap class path

I prefer the second solution because it is very simple.


Seems like some use case for aspect frameworks, no ?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜