错误和错误处理代表一类 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
),可能会混淆那些需要特殊处理的异常,或是捕获了不应在程序中这一点捕获的异常。本质上,捕获范围过大的异常与“.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 块会阻止编译器指出这一情况(有新的异常抛出)。除此以外,这个新的捕获块还可处理 ApplicationException
和 NullReferenceException
类型的异常,这些异常的发生并不在程序员的意料之内。Exception
),可能会混淆那些需要特殊处理的异常,或是捕获了不应在程序中这一点捕获的异常。本质上,捕获范围过大的异常与“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 连接相关的重要错误。如果没有显式地处理这些错误,连接会被处于一种意想不到的、潜在不安全的状态。