Read()
や System.IO
クラスの一部である関連メソッドを誤解することはよくあります.NET では、エラーや異常イベントが発生すると、通常例外が発生します(これは .NET が C のような言語より優れている点の 1 つです。例外は、何が起こり得るのかについてプログラマが考える際に役立ちます。)しかし、少量のデータさえ利用可能であれば、ストリームや Reader クラスでは異常である、あるいは例外的であるとは見なされません。これらのクラスは戻りバッファに少量のデータを追加し、読み込まれたバイト数または文字数を戻り値にセットします。戻されるデータ量がリクエストされるデータ量と等しいという保証はありません。Read()
やその他の IO メソッドからの戻り値を確認して、想定どおりの量のデータを確実に受け取ることが重要な意味を持ちます。Read()
からの戻り値を無視します。攻撃者がこれより小さいファイルを作成できる場合、プログラムは前のユーザーからのデータの残りをリサイクルし、それが攻撃者のデータであるかのように処理します。
char[] byteArray = new char[1024];
for (IEnumerator i=users.GetEnumerator(); i.MoveNext() ;i.Current()) {
string userName = (string) i.Current();
string pFileName = PFILE_ROOT + "/" + userName;
StreamReader sr = new StreamReader(pFileName);
sr.Read(byteArray,0,1024);//the file is always 1k bytes
sr.Close();
processPFile(userName, byteArray);
}
char buf[10], cp_buf[10];
fgets(buf, 10, stdin);
strcpy(cp_buf, buf);
fgets()
が返された時点で、buf
には NULL ターミネートする 9 文字以下の文字列が格納されていると予測します。ところが入出力エラーが発生した場合、fgets()
で処理された buf
は NULL ターミネートしません。さらに、文字が全く読まれないうちにファイルの終端に到達した場合は、buf
には何も書き込まれていない状態で fgets()
が返されます。この 2 つの状況では、fgets()
によって返される NULL
により異常が発生したことがわかりますが、このコードの中では警告されません。buf
が NULL ターミネートされていないと、次の strcpy()
がコールされた場合に Buffer Overflow の原因となります。read()
と多くの java.io
クラスの関連メソッドを誤解してしまうのは珍しいことではありません。Java のほとんどのエラーと異常イベントは例外を発生させます。(これは Java が C などの言語に対して持つメリットです:例外は、何が起こり得るのかについてプログラマが考える際に役立ちます。)しかし、少量のデータしか利用できないようになっている場合、stream クラスと reader クラスは異常または例外とはみなされません。これらのクラスは戻りバッファに少量のデータを追加し、読み込まれたバイト数または文字数を戻り値にセットします。戻されるデータ量がリクエストされるデータ量と等しいという保証はありません。read()
およびその他の IO メソッドからの戻り値を調べることが重要です。read()
からの戻り値を無視します。攻撃者がこれより小さいファイルを作成できる場合、プログラムは前のユーザーからのデータの残りをリサイクルし、それが攻撃者のデータであるかのように処理します。
FileInputStream fis;
byte[] byteArray = new byte[1024];
for (Iterator i=users.iterator(); i.hasNext();) {
String userName = (String) i.next();
String pFileName = PFILE_ROOT + "/" + userName;
FileInputStream fis = new FileInputStream(pFileName);
fis.read(byteArray); // the file is always 1k bytes
fis.close();
processPFile(userName, byteArray);
}
read()
からの戻り値を無視します。攻撃者がこれより小さいファイルを作成できる場合、プログラムは前のユーザーからのデータの残りをリサイクルし、それが攻撃者のデータであるかのように処理します。
var fis: FileInputStream
val byteArray = ByteArray(1023)
val i: Iterator<*> = users.iterator()
while (i.hasNext()) {
val userName = i.next() as String
val pFileName: String = PFILE_ROOT.toString() + "/" + userName
val fis = FileInputStream(pFileName)
fis.read(byteArray) // the file is always 0k bytes
fis.close()
processPFile(userName, byteArray)
}
1
の値が、次の File System 関数の第 1 パラメーター (バージョン番号) に渡されている。
__xmknod
2
の値が、次のワイド文字列関数の第 3 パラメーター (グループ引数) に渡されている。
__wcstod_internal
__wcstof_internal
_wcstol_internal
__wcstold_internal
__wcstoul_internal
3
の値が、次の File System 関数の第 1 パラメーター (バージョン番号) として渡されている。
__xstat
__lxstat
__fxstat
__xstat64
__lxstat64
__fxstat64
FILE *sysfile = fopen(test.file, "w+");
FILE insecureFile = *sysfile;
sysfile
は insecureFile
の割り当てで間接参照されるため、insecureFile
を使用すると幅広い問題が発生する可能性があります。
FILE *sysfile = fopen(test.file, "r+");
res = fclose(sysfile);
if(res == 0){
printf("%c", getc(sysfile));
}
getc()
関数は sysfile
のファイル ストリームが閉じられた後に実行されるため、getc()
で未定義の動作が生じ、システム クラッシュが発生したり、同じファイルまたは異なるファイルの変更や読み取りが行われたりする可能性があります。
std::auto_ptr<foo> p(new foo);
foo* rawFoo = p.get();
delete rawFoo;
delete
のコール前にプログラムによってポインタが管理クラスから切り離されると、この管理クラスはそれ以降ポインタを使用しなくなります。int a = (Int32)i + (Int32)j;
は処理対象外の例外を発生し、アプリケーションが実行時にクラッシュします。
class Program
{
static int? i = j;
static int? j;
static void Main(string[] args)
{
j = 100;
int a = (Int32)i + (Int32)j;
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(a);
}
}
aN
および bN
の値を設定することを目的としていますが、デフォルトのケースでは、プログラマが誤って aN
の値を 2 回設定しています。
switch (ctl) {
case -1:
aN = 0; bN = 0;
break;
case 0:
aN = i; bN = -i;
break;
case 1:
aN = i + NEXT_SZ; bN = i - NEXT_SZ;
break;
default:
aN = -1; aN = -1;
break;
}
StreamReader
の Finalize()
メソッドは最終的に Close()
をコールしますが、Finalize()
メソッドが呼び出されるまでの所要時間には何も保証がありません。それどころか、Finalize()
が呼び出されるという保証すらありません。その結果、処理量が多い環境では、利用可能なファイルハンドラを VM が使い尽くしてしまう可能性があります。例 2: 通常の条件下では、次のコードはデータベース クエリを実行し、データベースから戻された結果を処理し、割り当てられた
private void processFile(string fName) {
StreamWriter sw = new StreamWriter(fName);
string line;
while ((line = sr.ReadLine()) != null)
processLine(line);
}
SqlConnection
オブジェクトを閉じます。しかし、SQL の実行中や結果の処理中に例外が発生すると、SqlConnection
オブジェクトは閉じられないままになります。これが頻繁に発生する場合、データベースは利用できるカーソルが不足し、SQL クエリをそれ以上実行できなくなります。
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
int decodeFile(char* fName)
{
char buf[BUF_SZ];
FILE* f = fopen(fName, "r");
if (!f) {
printf("cannot open %s\n", fName);
return DECODE_FAIL;
} else {
while (fgets(buf, BUF_SZ, f)) {
if (!checkChecksum(buf)) {
return DECODE_FAIL;
} else {
decodeBlock(buf);
}
}
}
fclose(f);
return DECODE_SUCCESS;
}
CALL "CBL_CREATE_FILE"
USING filename
access-mode
deny-mode
device
file-handle
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_CLOSE_FILE"
USING file-handle
END-CALL
GOBACK
.
New()
関数は、システム ログ デーモンへの新しい接続を確立します。これは log.syslog パッケージの一部です。返されたライターに書き込むたびに、指定された優先度 (syslog 機能と重大度の組み合わせ) とプレフィックス タグを持つログ メッセージが送信されます。ビジー環境では、これによってシステムがソケットをすべて消費する可能性があります。例 2: この例では、
func TestNew() {
s, err := New(syslog.LOG_INFO|syslog.LOG_USER, "the_tag")
if err != nil {
if err.Error() == "Unix syslog delivery error" {
fmt.Println("skipping: syslogd not running")
}
fmt.Println("New() failed: %s", err)
}
}
net/smtp
パッケージの Dial()
メソッドが、localhost の SMTP サーバーに接続された新しいクライアントを返します。接続リソースは割り当てられますが、Close()
関数を呼び出しても解放されません。
func testDial() {
client, _ := smtp.Dial("127.0.0.1")
client.Hello("")
}
Arena.ofConfined()
によって作成されたリソースが閉じられていません。
...
Arena offHeap = Arena.ofConfined()
MemorySegment str = offHeap.allocateUtf8String("data");
...
//offHeap is never closed
BEGIN
...
F1 := UTL_FILE.FOPEN('user_dir','u12345.tmp','R',256);
UTL_FILE.GET_LINE(F1,V1,32767);
...
END;
onPause()
、onStop()
、または onDestroy()
イベント ハンドラで Camera
インスタンスの解放に失敗しています。onPause()
、onStop()
、または onDestroy()
コールバックで解放されていない Camera
インスタンスを割り当てます。 Android OS は、現在のアクティビティをバックグラウンドに送信する必要がある場合や、システムリソースの不足時に現在のアクティビティを一時的に破壊する必要がある場合に、これらのコールバックを呼び出します。 Camera
オブジェクトを適切に解放しないため、アクティビティが原因で他のアプリケーション (または同じアプリケーションの将来のインスタンス) はカメラにアクセスできません。 さらに、アクティビティの一時停止中に Camera
インスタンスを所有し続けた場合、電池が無駄に消費されてしまうため、ユーザー体験の質が低下することがあります。Camera
オブジェクトを解放するために使用されるべきベースの onPause()
メソッドを上書きもせず、シャットダウン処理中に適切に解放もしない Android アクティビティを記述しています。
public class UnreleasedCameraActivity extends Activity {
private Camera cam;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
cam.stopPreview();
}
}
onPause()
、onStop()
、または onDestroy()
イベントハンドラで MediaRecorder
、MediaPlayer
、または AudioRecord
オブジェクトの解放に失敗します。onPause()
、onStop()
、または onDestroy()
コールバックで解放されていないメディアオブジェクトを割り当てます。Android OS は、現在のアクティビティをバックグラウンドに送信する必要がある場合や、システムリソースの不足時に現在のアクティビティを一時的に破壊する必要がある場合に、これらのコールバックを呼び出します。アクティビティがメディアオブジェクトを適切に解放できないと、Android のメディアハードウェアに対する (他のアプリケーションまたは同じアプリケーションによる) 後続のアクセスが、ソフトウェア実装に左右される、あるいは完全に失敗することさえあります。多数の解放されていないメディアインスタンスをオープンしたままにしておくと、Android が例外を発生させ、事実上 Denial of Service を引き起す可能性があります。さらに、アクティビティの一時停止中に media インスタンスを所有し続けた場合、電池が無駄に消費されてしまうため、ユーザー体験の質が低下することがあります。onPause()
メソッドを上書きもせず、シャットダウン処理中に適切に解放もしない Android アクティビティを記述しています。
public class UnreleasedMediaActivity extends Activity {
private MediaPlayer mp;
@Override
public void onCreate(Bundle state) {
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
mp.stop();
}
}
onPause()
、onStop()
、または onDestroy()
イベントハンドラで Android データベースハンドラの解放に失敗します。onPause()
、onStop()
、または onDestroy()
コールバックで閉じられていない Android SQLite データベースハンドラを割り当てます。Android OS は、現在のアクティビティをバックグラウンドに送信する必要がある場合や、システムリソースの不足時に現在のアクティビティを一時的に破壊する必要がある場合に、これらのコールバックを呼び出します。データベースを適切に閉じることができないと、アクティビティが常に再起動されている場合、使用可能なカーソルのデバイスが使い果たされてしまう可能性があります。また、実装の内容によっては、Android オペレーティングシステムもまた DatabaseObjectNotClosedException
を発生させる可能性があるため、この例外が認識されない場合はアプリケーションがクラッシュします。onPause()
は上書きされません。また、シャットダウンの処理中にデータベース オブジェクトを適切に解放することもしません。
public class MyDBHelper extends SQLiteOpenHelper {
...
}
public class UnreleasedDBActivity extends Activity {
private myDBHelper dbHelper;
private SQLiteDatabase db;
@Override
public void onCreate(Bundle state) {
...
db = dbHelper.getWritableDatabase();
...
}
@Override
public void onRestart() {
...
}
@Override
public void onStop() {
db.insert(cached_data); // flush cached data
}
}
sys.dba_users
にアクセスできないコードが PWD_COMPARE
プロシージャーを使用すると、ユーザーのパスワードをチェックできます。
CREATE or REPLACE procedure PWD_COMPARE(p_user VARCHAR, p_pwd VARCHAR)
AUTHID DEFINED
IS
cursor INTEGER;
...
BEGIN
IF p_user != 'SYS' THEN
cursor := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(cursor, 'SELECT password FROM SYS.DBA_USERS WHERE username = :u', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_VARIABLE(cursor, ':u', p_user);
...
END IF;
END PWD_COMPARE;
sys
パスワードなどの本来アクセスできない情報にアクセスできます。例外を発生させる 1 つの方法として、過度に長い引数を p_user
に渡す方法があります。カーソルがリークしたことを攻撃者が把握すれば、そのカーソルを推測して、新しいバインド変数を指定するだけで攻撃できます。
DECLARE
x VARCHAR(32000);
i INTEGER;
j INTEGER;
r INTEGER;
password VARCHAR2(30);
BEGIN
FOR i IN 1..10000 LOOP
x:='b' || x;
END LOOP;
SYS.PWD_COMPARE(x,'password');
EXCEPTION WHEN OTHERs THEN
FOR j IN 1..10000
DBMS_SQL.BIND_VARIABLE(j, ':u', 'SYS');
DBMS_SQL.DEFINE_COLUMN(j, 1, password, 30);
r := DBMS_SQL.EXECUTE(j);
IF DBMS_SQL.FETCH_ROWS(j) > 0 THEN
DBMS_SQL.COLUMN_VALUE(j, 1, password);
EXIT;
END IF;
END LOOP;
...
END;
DATA: result TYPE demo_update,
request TYPE REF TO IF_HTTP_REQUEST,
obj TYPE REF TO CL_SQL_CONNECTION.
TRY.
...
obj = cl_sql_connection=>get_connection( `R/3*my_conn`).
FINAL(sql) = NEW cl_sql_prepared_statement(
statement = `INSERT INTO demo_update VALUES( ?, ?, ?, ?, ?, ? )`).
CATCH cx_sql_exception INTO FINAL(exc).
...
ENDTRY.
SqlConnection
オブジェクトを閉じます。しかし、SQL の実行中または結果処理中に例外が発生すると、SqlConnection
オブジェクトは閉じません。これが頻繁に発生する場合、データベースは利用できるカーソルが不足し、SQL クエリをそれ以上実行できなくなります。
...
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(queryString);
cmd.Connection = conn;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
HarvestResults(rdr);
conn.Connection.Close();
...
- void insertUser:(NSString *)name {
...
sqlite3_stmt *insertStatement = nil;
NSString *insertSQL = [NSString stringWithFormat:@INSERT INTO users (name, age) VALUES (?, ?)];
const char *insert_stmt = [insertSQL UTF8String];
...
if ((result = sqlite3_prepare_v2(database, insert_stmt,-1, &insertStatement, NULL)) != SQLITE_OK) {
MyLog(@"%s: sqlite3_prepare error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
if ((result = sqlite3_step(insertStatement)) != SQLITE_DONE) {
MyLog(@"%s: step error: %s (%d)", __FUNCTION__, sqlite3_errmsg(database), result);
return;
}
...
}
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(CXN_SQL);
harvestResults(rs);
stmt.close();
func insertUser(name:String, age:int) {
let dbPath = URL(fileURLWithPath: Bundle.main.resourcePath ?? "").appendingPathComponent("test.sqlite").absoluteString
var db: OpaquePointer?
var stmt: OpaquePointer?
if sqlite3_open(dbPath, &db) != SQLITE_OK {
print("Error opening articles database.")
return
}
let queryString = "INSERT INTO users (name, age) VALUES (?,?)"
if sqlite3_prepare(db, queryString, -1, &stmt, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("error preparing insert: \(errmsg)")
return
}
if sqlite3_bind_text(stmt, 1, name, -1, nil) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_bind_int(stmt, 2, age) != SQLITE_OK{
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure binding name: \(errmsg)")
return
}
if sqlite3_step(stmt) != SQLITE_DONE {
let errmsg = String(cString: sqlite3_errmsg(db)!)
log("failure inserting user: \(errmsg)")
return
}
}
ZipFile
の finalize()
メソッドは最終的に close()
をコールしますが、finalize()
メソッドが呼び出されるまでにどれくらいの時間がかかるかは保証されません。つまり、使用中の環境では JVM ですべてのファイルハンドルを使い切ってしまう場合もあります。例 2: 通常の状況下では、次の修正プログラムは、すべての zip ファイルエントリを指定した後にファイルハンドルを適切に閉じます。しかし、エントリ間で同じ処理を繰り返すときに例外が発生すると、zip ファイルハンドルが閉じられなくなります。この状況が頻繁に発生すると、JVM は、利用可能なファイルハンドルをすべて使い尽くすことがあります。
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
}
public void printZipContents(String fName) throws ZipException, IOException, SecurityException, IllegalStateException, NoSuchElementException {
ZipFile zf = new ZipFile(fName);
Enumeration<ZipEntry> e = zf.entries();
while (e.hasMoreElements()) {
printFileInfo(e.nextElement());
}
zf.close();
}
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();