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의 대처는 할 수 있다.
    h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s Chion s / 1938735 / Doe s-f Ree Ptr-U-Ptr-S-N-l

    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()의 안전성에 대해 기재하고 있는 블로그가 링크 끊어지고 있었다.
    h tp // w w. 게이오시치에 s. jp / ky_ 우비 d / c pp / 펑 게 / 012. HTML

    NULL로 초기화되고 있는 포인터를 delete 연산자로 지정하면 아무것도 일어나지 않는 것이 보증되고 있다.

    블로그 정보는 수년 만에 사라질 수 있어 유감이다.

    Free() 대신 delete 사용



    (추기 2017/10/31)

    @ 덴미 님의 의견을 바탕으로 찾은 자료에서 아래의 기재를 찾았습니다.

    C++ Builder의 Free Method

    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;
    

    null 포인터를 통한 멤버 함수 호출은 C ++ 사양에서 정의되지 않은 동작



    @ 사이토와 아츠시 님의 코멘트 에서 널 포인터로부터의 멤버 함수 호출시의 거동에 대해 상세하게 기재되어 있습니다.

    정보 감사입니다.

    Free() 를 사용하는 것으로 미정의의 거동이 되어, 디버그시에 곤란한 상황이 될 가능성이 있을 것 같습니다. 장래의 트러블 회피를 위해서는 Free()는 사용하지 않게 합시다.

    좋은 웹페이지 즐겨찾기