コードの質が低いと、予測できない動作につながります。ユーザーの視点には、それがしばしば使い勝手の悪さとなって現れます。攻撃者にとっては、予期せぬ方法でシステムにストレスを与える機会となります。
SafeEvpPKeyHandle
の新しいインスタンスを作成しますが、対応する DangerousRelease
の呼び出しを行わずに DangerousAddRef
メソッドを呼び出しています。例 2: 次のコードは、
var pkey = NativeMethods.ENGINE_LOAD_SSL_PRIVATE_KEY(...);
var safeEvpHandle = new SafeEvpPKeyHandle(handle: handle, ownsHandle: true);
bool success = false;
try {
safeEvpHandle.DangerousAddRef(ref success);
var handle = safeEvpHandle.DangerousGetHandle();
} catch (ObjectDisposedException ex) {
//...
} finally {
safeEvpHandle.close();
}
SafeEvpPKeyHandle
の新しいインスタンスを作成しますが、対応する DangerousAddRef
の呼び出しを行わずに DangerousRelease
メソッドを呼び出しています。
var pkey = NativeMethods.ENGINE_LOAD_SSL_PRIVATE_KEY(...);
var safeEvpHandle = new SafeEvpPKeyHandle(handle: handle, ownsHandle: true);
bool success = false;
try {
var handle = safeEvpHandle.DangerousGetHandle();
} catch (ObjectDisposedException ex) {
//...
} finally {
safeEvpHandle.DangerousRelease();
safeEvpHandle.close();
}
SafeEvpPKeyHandle
の新しいインスタンスを作成しますが、ownsHandle
パラメーターを false
に設定することによって完了処理フェーズ中にオブジェクトがハンドルを確実に解放できるようにすることはできません。
var pkey = NativeMethods.ENGINE_LOAD_SSL_PRIVATE_KEY(...);
var safeEvpHandle = new SafeEvpPKeyHandle(handle: handle, ownsHandle: false);
if (safeEvpHandle.IsInvalid) {
...
}
safeEvpHandle.close();
SafeEvpPKeyHandle
の新しいインスタンスを作成しますが、SetHandleAsInvalid
によってハンドルが無効化された後に DangerousGetHandle
を呼び出しており、古いハンドルの値が返される可能性があります。
var pkey = NativeMethods.ENGINE_LOAD_SSL_PRIVATE_KEY(...);
var safeEvpHandle = new SafeEvpPKeyHandle(handle: handle, ownsHandle: true);
...
safeEvpHandle.SetHandleAsInvalid();
...
var handle = safeEvpHandle.DangerousGetHandle();
...
safeEvpHandle.close();
DirectoryEntry
オブジェクトを閉じます。ただし、LDAP クエリの実行中または結果処理中に例外が発生すると、DirectoryEntry
オブジェクトは閉じません。DirectoryEntry
では Active Directory サーバーのクエリに COM API が内部的に使用されるため、これによりメモリ リークが発生します。
...
DirectoryEntry entry = new DirectoryEntry("LDAP://CN=users,DC=fabrikam,DC=com");
DirectorySearcher mySearcher = new DirectorySearcher(entry);
SearchResultCollection result = mySearcher.FindAll();
CheckUsers(result);
mySearcher.Dispose();
entry.Close();
...
...
lo_client = cl_apc_tcp_client_manager=>create( i_host = host
i_port = port
i_frame = lv_frame
i_protocol = protocol
i_ssl_id = ssl_id
i_event_handler = lo_event_handler ).
" initiate the connection setup, successful connect leads to execution of ON_OPEN
lo_client->connect( ).
...
例 2: 通常の状況下では、次の修正プログラムは、ソケットと関連するストリームを適切に閉じています。しかし、入力を読み取るときや画面にデータを書き込むときに例外が発生すると、ソケットオブジェクトが閉じられない場合があります。この状況が頻繁に発生すると、システムはソケットを使い果たし、それ以降の接続を処理できなくなります。
private void echoSocket(String host, int port) throws UnknownHostException, SocketException, IOException
{
Socket sock = new Socket(host, port);
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
while ((String socketData = reader.readLine()) != null) {
System.out.println(socketData);
}
}
private void echoSocket(String host, int port) throws UnknownHostException, SocketException, IOException
{
Socket sock = new Socket(host, port);
BufferedReader reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
while ((String socketData = reader.readLine()) != null) {
System.out.println(socketData);
}
sock.close();
}
StreamReader
の Finalize()
メソッドは最終的に Close()
をコールしますが、Finalize()
メソッドが呼び出されるまでにどれくらいの時間がかかるかは保証されません。それどころか、Finalize()
が呼び出されるという保証すらありません。その結果、処理量が多い環境では、利用可能なファイル ハンドラを VM が使い尽くしてしまう可能性があります。
private void processFile(string fName) {
StreamWriter sw = new StreamWriter(fName);
string line;
while ((line = sr.ReadLine()) != null)
processLine(line);
}
FileInputStream
の finalize()
メソッドは最終的に close()
をコールしますが、finalize()
メソッドが呼び出されるまでにどれくらいの時間がかかるかは保証されません。つまり、使用中の環境では JVM ですべてのファイル ハンドルを使い切ってしまう場合もあります。
private void processFile(String fName) throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream(fName);
int sz;
byte[] byteArray = new byte[BLOCK_SIZE];
while ((sz = fis.read(byteArray)) != -1) {
processBytes(byteArray, sz);
}
}
...
CFIndex numBytes;
do {
UInt8 buf[bufferSize];
numBytes = CFReadStreamRead(readStream, buf, sizeof(buf));
if( numBytes > 0 ) {
handleBytes(buf, numBytes);
} else if( numBytes < 0 ) {
CFStreamError error = CFReadStreamGetError(readStream);
reportError(error);
}
} while( numBytes > 0 );
...
def readFile(filename: String): Unit = {
val data = Source.fromFile(fileName).getLines.mkString
// Use the data
}
...
func leak(reading input: InputStream) {
input.open()
let bufferSize = 1024
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
while input.hasBytesAvailable {
let read = input.read(buffer, maxLength: bufferSize)
}
buffer.deallocate(capacity: bufferSize)
}
...
performOperationInCriticalSection()
の前にロックを確立しますが、このメソッドで例外が発生する場合にはロックを解放しません。
Object synchronizationObject = new Object ();
System.Threading.Monitor.Enter(synchronizationObject);
performOperationInCriticalSection();
System.Threading.Monitor.Exit(synchronizationObject);
int helper(char* fName)
{
int status;
...
pthread_cond_init (&count_threshold_cv, NULL);
pthread_mutex_init(&count_mutex, NULL);
status = perform_operation();
if (status) {
printf("%s", "cannot perform operation");
return OPERATION_FAIL;
}
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
return OPERATION_SUCCESS;
}
CALL "CBL_GET_RECORD_LOCK"
USING file-handle
record-offset
record-length
reserved
END-CALL
IF return-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
PERFORM write-data
IF ws-status-code NOT = 0
DISPLAY "Error!"
GOBACK
ELSE
DISPLAY "Success!"
END-IF
END-IF
CALL "CBL_FREE_RECORD_LOCK"
USING file-handle
record-offset
record-length
reserved
END-CALL
GOBACK
.
performOperationInCriticalSection()
の前にロックを確立しますが、このメソッドで例外が発生する場合にはロックを解放しません。
ReentrantLock myLock = new ReentrantLock ();
myLock.lock();
performOperationInCriticalSection();
myLock.unlock();
performOperationInCriticalSection()
の前にロックを確立しますが、決してそのロックを解放しません。
os_unfair_lock lock1 = OS_UNFAIR_LOCK_INIT;
os_unfair_lock_lock(&lock1);
performOperationInCriticalSection();
performOperationInCriticalSection()
の前にロックを確立しますが、決してそのロックを解放しません。
let lock1 = OSAllocatedUnfairLock()
lock1.lock()
performOperationInCriticalSection();
incomingStream
から管理対象の Bitmap オブジェクトを作成しています。この Bitmap は処理され、送信ストリーム outgoingStream
に残ります。incomingBitmap
および outgoingBitmap
の Dispose()
メソッドは明示的にコールされていません。Bitmap.Dispose()
をコールします。しかし、この Bitmap
オブジェクトは、まれな、管理対象外のシステム リソースを使用しています。そのため、ガベージ コレクタは、Dispose()
をコールできずに、管理対象外のリソース プールが枯渇してしまう可能性があります。
private void processBitmap(Stream incomingStream, Stream outgoingStream, int thumbnailSize)
{
Bitmap incomingBitmap = (Bitmap)System.Drawing.Image.FromStream(incomingStream);
bool validBitmap = validateBitmap(incomingBitmap);
if (!validBitmap)
throw new ValidationException(incomingBitmap);
Bitmap outgoingBitmap = new Bitmap(incomingBitmap, new Size(thumbnailSize, thumbnailSize));
outgoingBitmap.Save(outgoingStream, ImageFormat.Bmp);
}
char* ptr = (char*)malloc (SIZE);
...
if (err) {
abrt = 1;
free(ptr);
}
...
if (abrt) {
logError("operation aborted before commit", ptr);
}