如何在java程序中禁用堆栈跟踪生成?

时间:2010-02-23 12:19:49

标签: java debugging stack-trace

我想禁用在抛出异常时生成的堆栈跟踪。 我用了,

Runtime.getRuntime().traceInstructions(false);
Runtime.getRuntime().traceMethodCalls(false);

但我仍然可以看到跟踪生成。你怎么能这样做?此外,我需要检测是否有人正在调试我的课程。

我想禁用所有异常跟踪。我不能使用混淆,因为我的产品是一个将用于开发的SDK。我还提供了Runtime,当人们想要部署使用我的SDK构建的应用程序时,会使用它。我的要求是任何使用我的运行时jar的人都不应该能够调试编写的代码...或者至少我会通过避免从我的运行时jar生成堆栈跟踪来使调试变得困难。

我发现的一种方法是所有来自我的运行时jar的异常,我只是抓住它们并在异常对象上设置一个空的StackTraceElement数组并重新抛出它......

为什么有这样的要求? 假设您使用我的SDK开发应用程序。(SDK jar无法与您的应用程序捆绑在一起..我已经限制了它,那就是最终:) !!)现在要在客户端的机器上运行您的应用程序,您(或客户端)需要安装客户端计算机上的运行时并运行您的应用程序。现在如果你的客户使用我的Runtime jar开始开发他自己的应用程序怎么办这对我的生意构成威胁....这就是为什么这个可怕的要求。

为什么禁用堆栈跟踪?
通过禁用堆栈跟踪生成或方法调用跟踪生成,我想用我的Runtime jar开发代码很难,这就是为什么我以这种方式开始我的问题...建议一些其他解决方案来实现这样的要求...

6 个答案:

答案 0 :(得分:11)

我也很想知道你为什么要这样做,但如果你真的有理由,你至少有两个选择:

如果要为自己的Exception实现禁用堆栈跟踪生成,可以简单地覆盖fillInStackTrace方法:

public static class MyException extends Exception {
    @Override
    public Throwable fillInStackTrace() {
        return this;
    }       
}

如果要为所有异常禁用它,可以使用字节代码检测代理替换Throwable类中的fillInStackTrace方法。但这只适用于Java 6,因为不允许在Java 5中使用检测方法将Java方法替换为本机方法(fillInStackTrace)。

答案 1 :(得分:5)

  1. 我认为代码不可能知道它正在被调试,除非通过间接(和不可靠)的方式来测量执行代码序列所需的时间。

  2. 无法禁用所有堆栈跟踪。您可以为您自己定义的异常类禁用stracktraces,方法是覆盖Throwable.fillInStackTrace()不执行任何操作。 但这对于你无法改变的课程不起作用。

  3. 但如果你正在考虑做这些事情以防止逆向工程,即使你能做到这一点,你也会浪费你的时间。黑客很容易识别应用程序的反逆向工程代码并编辑相关的字节码文件以禁用它。

    编辑 - 我已经修改了我对你要做的事情的看法。鉴于您所做的是分发一个SDK,您期望客户将其嵌入到自己的应用程序中,禁用整个Java应用程序的堆栈跟踪将被视为客户恶意行为,IMO。作为保护“宝贵”IP的副作用,您使客户/开发人员难以调试自己的代码。即使代码在调用堆栈中没有您宝贵的方法!

    如果我是客户,我可能更愿意发送混淆代码而不是这样做。但最有可能的是,我会非常努力地找到一个替代软件供应商,没有将其付费用户视为小偷

答案 2 :(得分:2)

如果禁用堆栈跟踪生成,JVM中有一些复杂的部分(至少是Sun的JVM实现)不起作用(我在实现一些反射支持方法时看到了这一点)。所以我认为根本不能禁用堆栈跟踪生成。 Runtime.trace*()方法与其他方法有关(调试工具比堆栈跟踪更彻底)。

一般而言,只有通过字节码检测(在加载时使用额外指令修改字节码),才能透明地分析任何Java代码。对这种分析的唯一已知防御(我假设你试图保持你的代码内部机密)是混淆。例如,请参阅ProGuard。混淆会使堆栈跟踪对任何过度好奇的用户都无用(而且,遗憾的是,由于同样的原因,它也会使调试变得非常困难。)

答案 3 :(得分:1)

是否要为所有例外禁用它?

在不知道你想要实现的目标的情况下,我会说这是走错路。如果你期望抛出异常,你很乐意忽略它,你应该明确地捕获并处理它(处理它只是意味着忽略它,或者记录没有完整堆栈跟踪的短消息)。

答案 4 :(得分:1)

您可以将所有例外重定向到其他位置,例如:

Thread.setDefaultUncaughtExceptionHandler(
                (t, e) -> System.err.println("There's nothing to see here"));

或者简单地说:

Thread.setDefaultUncaughtExceptionHandler(null);

注意:永远不要在制作中使用上述代码,除非您想给同事们带来困难

答案 5 :(得分:0)

Throwable.setStackTrace(StackTraceElement [] stackTrace)将在调用后阻止对stackTrace的任何添加:

Throwable t = new Throwable();
StackTraceElement[] myStackTrace = new StackTraceElement[] {
 new StackTraceElement("MySDKClass","MySDKMethod","MySDKFile",0)
};
t.setStackTrace(trace);