錯誤和錯誤處理代表一種 API 類別。與錯誤處理相關的錯誤非常普遍,所以它們應該擁有自己的特殊領域。如同「API 濫用」,有兩種方法可以引入與錯誤相關的安全漏洞:最常見的一種方法是不當處理錯誤 (或根本沒有處理)。第二種是產生錯誤,這些錯誤不是給的資訊太多 (給可能的攻擊者),就是問題難以處理。
...
EXEC CICS
INGNORE CONDITION ERROR
END-EXEC.
...
doExchange()
拋出的罕見異常。
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
,程式會繼續執行,就像什麼都沒有發生過一樣。程式不會記錄有關此特殊情況,這將使得事後嘗試尋找程式此異常的運作方式變得很困難。DoExchange()
拋出的罕見異常。
try {
DoExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
,程式會繼續執行,就像什麼都沒有發生過一樣。程式不會記錄有關此特殊情況,這將使得事後嘗試尋找程式此異常的運作方式變得很困難。doExchange()
拋出的罕見異常。
try {
doExchange();
}
catch (RareException e) {
// this can never happen
}
RareException
,程式會繼續執行,就像什麼都沒有發生過一樣。程式不會記錄有關此特殊情況,這將使得事後嘗試尋找程式此異常的運作方式變得很困難。doExchange()
拋出的罕見異常。
try {
doExchange();
}
catch (exception $e) {
// this can never happen
}
RareException
,程式會繼續執行,就像什麼都沒有發生過一樣。程式不會記錄有關此特殊情況,這將使得事後嘗試尋找程式此異常的運作方式變得很困難。open()
拋出的罕見異常。
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except:
# This will never happen
pass
RareException
,程式會繼續執行,就像什麼都沒有發生過一樣。程式不會記錄有關此特殊情況,這將使得事後嘗試尋找程式此異常的運作方式變得很困難。
PROCEDURE do_it_all
IS
BEGIN
BEGIN
INSERT INTO table1 VALUES(...);
COMMIT;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
END do_it_all;
Exception
)「濃縮」catch 區塊,可能會混淆那些需要特殊處理的異常,或是捕捉了不應該在程式中某階段捕捉的異常。捕捉範圍過大的異常,實質上是與「.NET 分類定義異常」目的相違背的,並且隨著程式的增長且開始拋出新類型的異常時,此做法將導致嚴重的危險。因為,新的異常類型將不會被注意到。
try {
DoExchange();
}
catch (IOException e) {
logger.Error("DoExchange failed", e);
}
catch (FormatException e) {
logger.Error("DoExchange failed", e);
}
catch (TimeoutException e) {
logger.Error("DoExchange failed", e);
}
try {
DoExchange();
}
catch (Exception e) {
logger.Error("DoExchange failed", e);
}
DoExchange()
後而拋出新的異常類型,而此異常需以不同方式來處理,那麼過大範圍的 catch 區塊將會阻止編譯器指出這個情況 (有新的異常拋出)。此外,新的 catch 區塊也可處理 ApplicationException
和 NullReferenceException
類型的異常,而處理這些異常並不在程式設計師的意圖之內。Exception
)「濃縮」catch 區塊,可能會混淆那些需要特殊處理的異常,或是捕捉了不應該在程式中某階段捕捉的異常。捕捉範圍過大的異常,實質上是與「Java 分類定義異常」目的相違背的,並且隨著程式的增長且開始拋出新類型的異常時,此做法將導致嚴重的危險。因為,新的異常類型將不會被注意到。
try {
doExchange();
}
catch (IOException e) {
logger.error("doExchange failed", e);
}
catch (InvocationTargetException e) {
logger.error("doExchange failed", e);
}
catch (SQLException e) {
logger.error("doExchange failed", e);
}
try {
doExchange();
}
catch (Exception e) {
logger.error("doExchange failed", e);
}
doExchange()
後而拋出新的異常類型,而此異常需以不同方式來處理,那麼過大範圍的 catch 區塊將會阻止編譯器指出這個情況 (有新的異常拋出)。此外,新的 catch 區塊也可處理從 RuntimeException
衍生的異常,例如 ClassCastException
和 NullPointerException
,而處理這些異常並不在程式設計師的意圖之內。Exception
或是 Throwable
異常的方法,會使呼叫者很難處理和修復發生的錯誤。Java 的異常機制被設定為:呼叫者可以很容易的預計到方法有可能會發生什麼錯誤,並且編寫程式碼以處理各個特定的異常情況。同時聲明:一個方法拋出一個過於籠統的異常違反該系統。
public void doExchange()
throws IOException, InvocationTargetException,
SQLException {
...
}
public void doExchange()
throws Exception {
...
}
doExchange()
方法因為變更了程式碼,而引入一個需要不同處理方式的異常,則不能用簡單的方式來處理該要求。NullPointerException
不是個好方法。NullPointerException
: NullPointerException
異常狀況來提醒出現錯誤情況。NullPointerException
。
try {
mysteryMethod();
}
catch (NullPointerException npe) {
}
NullReferenceException
不是個好方法。NullReferenceException
: NullReferenceException
異常狀況來提醒出現錯誤情況。NullReferenceException
。
try {
MysteryMethod();
}
catch (NullReferenceException npe) {
}
finally
區塊中回傳,會導致異常遺失。finally
區塊中的回傳指令,會導致 try 區塊中所拋出的任意異常遭丟棄。doMagic
方法,同時將 true
參數傳送給該方法,會導致拋出 MagicException
異常,該異常將不會傳送給呼叫者。finally
區塊中的回傳指令,會導致異常遭丟棄。
public class MagicTrick {
public static class MagicException extends Exception { }
public static void main(String[] args) {
System.out.println("Watch as this magical code makes an " +
"exception disappear before your very eyes!");
System.out.println("First, the kind of exception handling " +
"you're used to:");
try {
doMagic(false);
} catch (MagicException e) {
// An exception will be caught here
e.printStackTrace();
}
System.out.println("Now, the magic:");
try {
doMagic(true);
} catch (MagicException e) {
// No exception caught here, the finally block ate it
e.printStackTrace();
}
System.out.println("tada!");
}
public static void doMagic(boolean returnFromFinally)
throws MagicException {
try {
throw new MagicException();
}
finally {
if (returnFromFinally) {
return;
}
}
}
}
finally
區塊中回傳,會導致異常遺失。finally
區塊中的回傳陳述式,會導致 try 區塊中所拋出的任何異常遭丟棄。doMagic
,同時將 True
參數傳遞給該方法,會導致拋出 exception
異常,該異常將不會傳送給呼叫者。finally
區塊中的回傳陳述式,會導致異常遭丟棄。"disappear before your very eyes!" . PHP_EOL;
echo "First, the kind of exception handling " .
"you're used to:" . PHP_EOL;
try {
doMagic(False);
} catch (exception $e) {
// An exception will be caught here
echo $e->getMessage();
}
echo "Now, the magic:" . PHP_EOL;
try {
doMagic(True);
} catch (exception $e) {
// No exception caught here, the finally block ate it
echo $e->getMessage();
}
echo "Tada!" . PHP_EOL;
function doMagic($returnFromFinally) {
try {
throw new Exception("Magic Exception" . PHP_EOL);
}
finally {
if ($returnFromFinally) {
return;
}
}
}
?>
ThreadDeath
錯誤,有問題的執行緒可能並未真正停止。ThreadDeath
錯誤。如果出現 ThreadDeath
錯誤,請務必重新拋出該錯誤來真正停止執行緒。拋出 ThreadDeath
的用意為停止執行緒。如果接收 ThreadDeath
,就會導致執行緒持續執行並造成意外行為,因為原來拋出 ThreadDeath
的使用者想停止該執行緒。ThreadDeath
,但並未重新拋出。
try
{
//some code
}
catch(ThreadDeath td)
{
//clean up code
}
finally
區塊內使用 throw
指令會透過 try-catch-finally
中斷邏輯次序。finally
區塊永遠會在對應 try-catch
區塊後執行,而且通常用來釋放已配置資源,例如檔案控制碼或資料庫指標。在 finally
區塊中拋出異常,可以略過重要的清除程式碼,這是因為將中斷正常程式執行。 FileNotFoundException
時,會略過呼叫 stmt.close()
。
public void processTransaction(Connection conn) throws FileNotFoundException
{
FileInputStream fis = null;
Statement stmt = null;
try
{
stmt = conn.createStatement();
fis = new FileInputStream("badFile.txt");
...
}
catch (FileNotFoundException fe)
{
log("File not found.");
}
catch (SQLException se)
{
//handle error
}
finally
{
if (fis == null)
{
throw new FileNotFoundException();
}
if (stmt != null)
{
try
{
stmt.close();
}
catch (SQLException e)
{
log(e);
}
}
}
}
javax.net.ssl.SSLHandshakeException
、javax.net.ssl.SSLKeyException
和 javax.net.ssl.SSLPeerUnverifiedException
都會傳達與 SSL 連線相關的重要錯誤。如果沒有明確地處理這些錯誤,連線可能會處於一種非預期且潛在不安全的狀態。