簡體   English   中英

如何在 Java 程序中禁用堆棧跟蹤生成?

[英]How to disable stack trace generation in a java program?

我想禁用引發異常時生成的堆棧跟蹤。 我用過了,

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

但我仍然可以看到生成的痕跡。 你怎么能這樣做? 我還需要檢測是否有人在調試我的課程。

我想禁用所有異常跟蹤。 我不能使用混淆,因為我的產品是一個將用於開發的 SDK。 我還提供了一個運行時,當人們想要部署使用我的 SDK 構建的應用程序時,會使用它。 我的要求是任何使用我的運行時 jar 的人都不能調試編寫的代碼……或者至少我會通過避免從我的運行時 jar 中生成堆棧跟蹤來使調試變得困難。

我發現的一種方法是,所有源自我的運行時 jar 的異常,我只會捕獲它們並在異常對象上設置一個空的 StackTraceElement 數組並重新拋出它......

為什么有這樣的要求? 假設您使用我的 SDK 開發一個應用程序。(SDK jars 不能與您的應用程序捆綁在一起。在客戶端機器上運行並運行您的應用程序。 現在,如果您的客戶開始使用我的運行時 jar 開發他自己的應用程序怎么辦!! 那是對我的生意的威脅....這就是為什么可怕的要求。

為什么要禁用堆棧跟蹤?
通過禁用堆棧跟蹤生成或方法調用跟蹤生成,我想讓用我的運行時 jar 開發代碼變得困難,這就是為什么我以這種方式開始我的問題......建議一些其他解決方案來實現這樣的要求......

我也很好奇你為什么要這樣做,但如果你真的有你的理由,你至少有兩個選擇:

如果您想為自己的異常實現禁用堆棧跟蹤生成,您可以簡單地覆蓋 fillInStackTrace 方法:

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

如果要針對所有異常禁用它,可以使用字節碼檢測代理替換 Throwable 類中的 fillInStackTrace 方法。 但是,這僅適用於 Java 6,因為在 Java 5 中不允許使用檢測的 Java 方法替換本機方法 (fillInStackTrace)。

  1. 我認為代碼不可能知道它正在被調試,除非通過間接(並且不可靠)的方式,比如測量執行代碼序列需要多長時間。

  2. 不可能禁用所有堆棧跟蹤。 可以通過覆蓋Throwable.fillInStackTrace()不執行任何操作禁用您自己定義的異常類的 stracktraces。 但這不適用於您無法更改的課程。

但是如果你正在考慮做這些事情來防止逆向工程,即使你能做到,你也是在浪費時間。 黑客很容易識別您的應用程序的反逆向工程代碼並編輯相關的字節碼文件以禁用它。

編輯- 我已經修改了我對你正在嘗試做的事情的看法。 鑒於您正在分發一個 SDK,您希望您的客戶將其嵌入到他們自己的應用程序中,禁用整個 Java 應用程序的堆棧跟蹤被視為客戶敵對行為,IMO。 作為保護“寶貴”IP 的副作用,您使客戶/開發人員難以調試自己的代碼。 即使是調用堆棧中沒有您寶貴方法的代碼!

如果我是客戶,我可能更喜歡你發布混淆代碼而不是這樣做。 但最有可能的是,我會非常努力地尋找替代軟件供應商,該供應商不會將其付費客戶視為小偷

如果禁用堆棧跟蹤生成,JVM 有一些復雜的部分(至少是 Sun 的 JVM 實現)將無法工作(我在一些反射支持方法的實現中看到了這一點)。 所以我認為根本不能禁用堆棧跟蹤生成。 Runtime.trace*()方法是關於別的東西(一個比堆棧跟蹤更徹底的調試工具)。

總的來說,任何 Java 代碼都可以被透明地分析,只要通過字節碼檢測(加載時用額外指令修改字節碼)。 唯一已知的針對此類分析的防御措施(我假設您正在嘗試對代碼內部保密)是混淆。 參見例如ProGuard 混淆將使任何過度好奇的用戶都無法使用堆棧跟蹤(而且,遺憾的是,出於同樣的原因,它也使調試變得非常困難)。

Throwable.setStackTrace(StackTraceElement[] stackTrace) 將在調用后阻止對 stackTrace 的任何添加:

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

你想為所有例外禁用它嗎?

在不知道您想要實現什么的情況下,我會說這是錯誤的道路。 如果您希望拋出一個您樂於忽略的異常,您應該明確捕獲它並處理它(處理它可以簡單地意味着忽略它,或者記錄一條沒有完整堆棧跟蹤的短消息)。

您可以將所有異常重定向到不同的位置,例如:

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

或者干脆:

Thread.setDefaultUncaughtExceptionHandler(null);

注意:永遠不要在生產中使用上面的代碼,除非你想讓你的同事很難過

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM