C++ Builder > 無効なポインタ操作 > 不定値でのFree()によるメモリ破壊 > その後の処理で「無効なポインタ操作」 | Free()でなくdeleteを使う | ヌルポインタ経由でのメンバ関数呼び出しはC++の仕様上は未定義の挙動
C++ Builder XE4
発生条件
- 読込みファイルが空の時発生
原因
TJSONObject *jsonObj;
String jsonKey, jsonValue;
TJSONPair *pairObj;
for(int li=0; li < slread->Count; li++) { // file line index
String jsonText = slread->Strings[li];
// フォルダに使われる"\"の扱いによるエラー対応のため
jsonText = StringReplace(jsonText, L"\\", L"\\\\", TReplaceFlags()<<rfReplaceAll);
jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));
for(int pi=0; pi < jsonObj->Size(); pi++) { // pair index
pairObj = jsonObj->Get(pi);
jsonKey = pairObj->JsonString->Value();
jsonValue = pairObj->JsonValue->Value();
// debug_outputDebugString(dbgFormName + L":Load2", String(jsonKey + L":" + jsonValue));
m_json->AddPair(jsonKey, jsonValue);
}
}
jsonObj->Free();
slread->Countが0の時、jsonObjには不定値が入ったままになる。
その不定値を用いてFree()するため、メモリが破壊され、その後の動作で「無効なポインタ操作」が発生しているようだ。
jsonObj宣言時にNULLを入れておくと、Freeの対処はできる。
https://stackoverflow.com/questions/1938735/does-freeptr-where-ptr-is-null-corrupt-memory
7.20.3.2 The free function
...
The free function causes the space pointed to by ptr to be deallocated, that is, made available for further allocation. If ptr is a null pointer, no action occurs.
See ISO-IEC 9899.
もともとは宣言時にnew TJSONObject()
を代入していたコードであったが、それはメモリリークを発生すると気づき修正した。その修正時に宣言時のNULL代入を忘れて、今回の症状が出るまで気づかなかった。
所感
NULLでのFree()の安全性について記載しているブログがリンク切れになっていた。
http://www.geocities.jp/ky_webid/cpp/language/012.html
NULLで初期化されているポインタをdelete演算子に指定すると何も起こらないことが保証されている。
ブログの情報は数年で消える場合もあり残念だ。
Free()でなくdeleteを使う
(追記 2017/10/31)
@tenmyo さんのコメントをもとに見つけた資料で以下の記載を見つけました。
Note: In C++ code, do not use System::TObject::Free to destroy an object. Use the delete keyword.
C++のコードではFree()でなくdeleteを使うように、とのことです。
TJSONObject *jsonObj = NULL;
String jsonKey, jsonValue;
TJSONPair *pairObj = NULL;
for(int li=0; li < slread->Count; li++) { // file line index
String jsonText = slread->Strings[li];
// フォルダに使われる"\"の扱いによるエラー対応のため
jsonText = StringReplace(jsonText, L"\\", L"\\\\", TReplaceFlags()<<rfReplaceAll);
jsonObj = dynamic_cast<TJSONObject*>(TJSONObject::ParseJSONValue(jsonText));
for(int pi=0; pi < jsonObj->Size(); pi++) { // pair index
pairObj = jsonObj->Get(pi);
jsonKey = pairObj->JsonString->Value();
jsonValue = pairObj->JsonValue->Value();
// debug_outputDebugString(dbgFormName + L":Load2", String(jsonKey + L":" + jsonValue));
m_json->AddPair(jsonKey, jsonValue);
}
}
delete jsonObj;
ヌルポインタ経由でのメンバ関数呼び出しはC++の仕様上は未定義の挙動
@SaitoAtsushi さんのコメントにてヌルポインタからのメンバ関数呼び出し時の挙動について詳細が記載されています。
情報感謝です。
Free()を使うことで未定義の挙動になり、デバッグ時に困難な状況になる可能性がありそうです。将来のトラブル回避のためにはFree()は使わないようにしましょう。
Author And Source
この問題について(C++ Builder > 無効なポインタ操作 > 不定値でのFree()によるメモリ破壊 > その後の処理で「無効なポインタ操作」 | Free()でなくdeleteを使う | ヌルポインタ経由でのメンバ関数呼び出しはC++の仕様上は未定義の挙動), 我々は、より多くの情報をここで見つけました https://qiita.com/7of9/items/4d47d3f8013c67d630fa著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .