エラーとエラー処理は、API のクラスを表しています。エラー処理に関連するエラーは、非常に一般的であるため、独自の特別な分野を用意する必要があります。API の悪用と同様に、エラーに関連するセキュリティ脆弱性を引き起こす方法は 2 つあります。最も一般的な方法は、エラーを適切に処理しない (またはまったく処理しない) ことです。もうひとつは、(可能性のある攻撃者に) 過剰な情報を与えるエラーか、処理が困難なエラーを生成することです。
...
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 ブロックは ClassCastException
や NullPointerException
などの RuntimeException
からの例外も扱うようになります。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
ブロック内部に return ステートメントがあると、try ブロックで発生する例外が破棄される原因となります。doMagic
への 2 番目のコールによって発生する MagicException
、およびそのとき渡される true
は、コールする側には渡りません。finally
ブロック内の return ステートメントは、例外を破棄させます。
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
ブロック内部に return ステートメントがあると、try ブロックで発生する例外が破棄される原因となります。doMagic
への 2 番目のコールによって発生する exception
、およびそのとき渡される True
は、コールする側には渡りません。finally
ブロック内の return ステートメントは、例外を破棄させます。"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 接続に関連する重要なエラーを伝達します。これらのエラーが明示的に処理されない場合、接続が予期しない状態で残されたままとなり、セキュリティ上安全ではない状態になる可能性があります。