C ++狡猟さず愛、それずも䜕がうたくいかないのか





「Cを䜿甚するず、足を簡単に撃぀こずができたす。C ++でこれを行うのは難しいですが、足党䜓が倖れたす。」-BjörnStroustrup、C ++クリ゚ヌタヌ。


この蚘事では、安定した、安党で信頌性の高いコヌドを䜜成する方法ず、実際に意図せずに完党に砎壊するこずがいかに簡単であるかを瀺したす。このために、私たちは最も有甚で魅力的な資料を収集しようずしたした。







SimbirSoftでは、Secure Code Warriorプロゞェクトず緊密に連携しお、安党な゜リュヌションを䜜成するために他の開発者をトレヌニングしおいたす。特にHabrに぀いおは、CodeProject.comポヌタル甚に著者が曞いた蚘事を翻蚳したした。



だからコヌドに



これは抜象的なC ++コヌドの小さな郚分です。このコヌドは、非垞に実際のプロゞェクトで芋぀かる可胜性のあるあらゆる皮類の問題ず脆匱性を瀺すために特別に䜜成されたした。ご芧のずおり、これはWindows DLLコヌドですこれは重芁なポむントです。誰かがこのコヌドを䜕らかのもちろん安党な゜リュヌションで䜿甚するずしたす。



コヌドを詳しく芋おみたしょう。あなたの意芋では、䜕がうたくいかない可胜性がありたすか



コヌド
class Finalizer
{
    struct Data
    {
        int i = 0;
        char* c = nullptr;
        
        union U
        {
            long double d;
            
            int i[sizeof(d) / sizeof(int)];
            
            char c [sizeof(i)];
        } u = {};
        
        time_t time;
    };
    
    struct DataNew;
    DataNew* data2 = nullptr;
    
    typedef DataNew* (*SpawnDataNewFunc)();
    SpawnDataNewFunc spawnDataNewFunc = nullptr;
    
    typedef Data* (*Func)();
    Func func = nullptr;
    
    Finalizer()
    {
        func = GetProcAddress(OTHER_LIB, "func")
        
        auto data = func();
        
        auto str = data->c;
        
        memset(str, 0, sizeof(str));
        
        data->u.d = 123456.789;
        
        const int i0 = data->u.i[sizeof(long double) - 1U];
        
        spawnDataNewFunc = GetProcAddress(OTHER_LIB, "SpawnDataNewFunc")
        data2 = spawnDataNewFunc();
    }
    
    ~Finalizer()
    {
        auto data = func();
        
        delete[] data2;
    }
};

Finalizer FINALIZER;

HMODULE OTHER_LIB;
std::vector<int>* INTEGERS;

DWORD WINAPI Init(LPVOID lpParam)
{
    OleInitialize(nullptr);
    
    ExitThread(0U);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
    static std::vector<std::thread::id> THREADS;
    
    switch (fdwReason)
    {
        case DLL_PROCESS_ATTACH:
            CoInitializeEx(nullptr, COINIT_MULTITHREADED);
            
            srand(time(nullptr));
            
            OTHER_LIB = LoadLibrary("B.dll");
            
            if (OTHER_LIB = nullptr)
                return FALSE;
            
            CreateThread(nullptr, 0U, &Init, nullptr, 0U, nullptr);
        break;
        
        case DLL_PROCESS_DETACH:
            CoUninitialize();
            
            OleUninitialize();
            {
                free(INTEGERS);
                
                const BOOL result = FreeLibrary(OTHER_LIB);
                
                if (!result)
                    throw new std::runtime_error("Required module was not loaded");
                
                return result;
            }
        break;
        
        case DLL_THREAD_ATTACH:
            THREADS.push_back(std::this_thread::get_id());
        break;
        
        case DLL_THREAD_DETACH:
            THREADS.pop_back();
        break;
    }
    return TRUE;
}

__declspec(dllexport) int Initialize(std::vector<int> integers, int& c) throw()
{
    for (int i : integers)
        i *= c;
    
    INTEGERS = new std::vector<int>(integers);
}

int Random()
{
    return rand() + rand();
}

__declspec(dllexport) long long int __cdecl _GetInt(int a)
{
    return 100 / a <= 0 ? a : a + 1 + Random();
}




おそらく、このコヌドは単玔で、明癜で、十分に安党だず思いたしたかたたは倚分あなたはそれにいく぀かの問題を芋぀けたしたかそれずも、1、2、2぀ですか



このスニペットには、実際にはさたざたな皋床の重芁性を持぀43を超える朜圚的な脅嚁がありたす。







泚意すべき点



1sizeofddはlong doubleは、必ずしもsizeofintの倍数である必芁はありたせん。



int i[sizeof(d) / sizeof(int)];


この状況は、ここではテストも凊理もされおいたせん。たずえば、䞀郚のプラットフォヌムでは、long doubleが10バむトになる堎合がありたすこれは、MS VSコンパむラには圓おはたりたせんが、以前はC ++ Builderず呌ばれおいたRADStudioには圓おはたりたす。intは、プラットフォヌムに応じおサむズが異なる堎合もありたす䞊蚘のコヌドは、Windows甚であるため、この特定の状況に関連しお、問題は倚少䞍自然ですが、ポヌタブルコヌドの堎合、この問題は非垞に関連性がありたす。 いわゆるタむピングパンを䜿甚したい堎合、これらすべおが問題になる可胜性がありたす。ちなみに、それは未定矩の動䜜を匕き起こしたす







C ++蚀語暙準に準拠。ただし、最近のコンパむラは通垞、特定のケヌスに察しお正しい予想される動䜜を定矩するため、タむピングパンを䜿甚するのが䞀般的な方法ですたずえば、GCCが定矩するように。出兞Medium.com ちなみに、C ++ずは異なり、珟代のCでは、タむピングパンは完党に受け入れられたすC ++ずCは異なる蚀語であり、C ++を知っおいる堎合は、Cを知っおいるず期埅すべきではありたせん。逆ですよね解決策static_assertを䜿甚したす















コンパむル時にそのようなすべおの仮定を制埡したす。タむプサむズに問題がある堎合は譊告が衚瀺されたす。



static_assert(0U == (sizeof(d) % sizeof(int)), “Houston, we have a problem”);


2time_tはマクロであり、Visual Studioでは、32ビット叀いたたは64ビット新しいの敎数型を参照できたす。



time_t time;


2぀のバむナリがこのタむプの異なる物理衚珟でコンパむルされおいる堎合、異なる実行可胜モゞュヌルたずえば、実行可胜ファむルずそれがロヌドするDLLからこのタむプの倉数にアクセスするず、オブゞェクトの境界倖で読み取り/曞き蟌みが発生する可胜性がありたす。これにより、メモリの砎損やガベヌゞの読み取りが発生したす。







解決策すべおのモゞュヌル間のデヌタ亀換に、厳密に定矩された同じタむプのサむズが䜿甚されおいるこずを確認しおください。



int64_t time;


3B.DLLで栌玍されおいるのハンドルOTHER_LIB倉数しおいない、ただされお私たちは、このラむブラリの関数のアドレスを取埗するこずはできたせんので、我々は䞊蚘の倉数にアクセスするずきにロヌドされた



4静的オブゞェクトの初期化順序に問題SIOFOTHER_LIBオブゞェクト初期化される前にコヌドで䜿甚されおいたした



func = GetProcAddress(OTHER_LIB, "func");


FINALIZERは、DllMain関数を呌び出す前に䜜成される静的オブゞェクトです。そのコンストラクタヌでは、ただロヌドされおいないラむブラリヌを䜿甚しようずしおいたす。この問題は、静的FINALIZERによっお䜿甚される静的OTHER_LIBがダりンストリヌムの倉換ナニットに配眮されるずいう事実によっお悪化したす。これは、埌で初期化れロ化されるこずも意味したす。぀たり、アクセス時に、疑䌌ランダムガベヌゞが含たれたす。WinAPI䞀般に、これに正垞に反応するはずです。なぜなら、高い確率で、そのような蚘述子を持぀ロヌドされたモゞュヌルがたったく存圚しないからです。そしお、絶察に信じられないほどの偶然が起こったずしおも、それが「Func」ずいう名前の関数を含む可胜性は䜎いです。



解決策䞀般的なアドバむスは、特にDLLで盞互に䟝存しおいる堎合は特に、グロヌバルオブゞェクト、特に耇雑なオブゞェクトの䜿甚を避けるこずです。ただし、䜕らかの理由でそれでも必芁な堎合は、初期化の順序に现心の泚意を払っおください。この順序を制埡するには、グロヌバルオブゞェクトのすべおのむンスタンス定矩を1぀の 倉換単䜍に配眮したすそれらが正しく初期化されるこずを保蚌するために正しい順序で。



5以前に返された結果は䜿甚前にチェックされたせん



auto data = func();


funcは関数ポむンタです。たた、B.dllの関数を指しおいる必芁がありたす。ただし、前の手順ですべおを完党に倱敗したため、これはnullptrになりたす。したがっお、予期された関数呌び出しの代わりに、それを逆参照しようずするず、アクセス違反たたは䞀般的な保護障害などが発生したす。



解決策倖郚コヌドこの堎合はWinAPIを操䜜するずきは、呌び出された関数の戻り結果を垞に確認しおください。信頌性が高く、障害に匷いシステムの堎合、このルヌルは、[䜕をい぀返すかに぀いお]厳密な契玄が結ばれおいる機胜にも適甚されたす。



6異なる配眮/パディング蚭定でコンパむルされたモゞュヌル間でデヌタを亀換するずきのガベヌゞの読み取り/曞き蟌み



auto str = data->c;


デヌタ構造通信モゞュヌル間で情報を亀換するために䜿甚されるにこれらの同じモゞュヌルが異なる物理的衚瀺である堎合、前述のすべおのアクセス違反、゚ラヌメモリ保護、障害セグメンテヌション、ヒヌプ砎損などが発生したす。たたは、ゎミを読むだけです。正確な結果は、このメモリの実際の䜿甚シナリオによっお異なりたす。構造自䜓に明瀺的な配眮/パディング蚭定がないため、これはすべお発生する可胜性がありたす。したがっお、コンパむル時のこれらのグロヌバル蚭定が盞互䜜甚するモゞュヌルで異なる堎合、問題が発生したす。







決定すべおの共有デヌタ構造が匷力で明瀺的に定矩された明癜な物理的衚珟固定サむズタむプ、明瀺的に指定された配眮などを䜿甚を持っおいるこず、および/たたは盞互運甚可胜なバむナリが同じグロヌバル配眮蚭定でコンパむルされおいるこずを確認しおください/ 充填。



も参照しおください
Alignment (C++ Declarations)

Data structure alignment

Struct padding in C++



7配列自䜓のサむズではなく、配列ぞのポむンタのサむズを䜿甚する



memset(str, 0, sizeof(str));


これは通垞、些现なタむプミスの結果です。ただし、この問題は、静的倚態性を凊理する堎合、たたはautoキヌワヌドを無意識に䜿甚する堎合特に明らかに䜿いすぎおいる堎合にも発生する可胜性がありたす。ただし、最新のコンパむラは、内郚静的アナラむザの機胜を䜿甚しお、コンパむル時にこのような問題を怜出するのに十分なほどスマヌトであるこずを期埅したいず思いたす。



決定



  • sizeof<完党なオブゞェクトタむプ>ずsizeof<オブゞェクトポむンタタむプ>を混同しないでください。
  • コンパむラの譊告を無芖しないでください;

  • typeid、constexpr、およびstatic_assertを組み合わせお、C ++ボむラヌプレヌトの魔法を少し䜿甚しお、コンパむル時に型が正しいこずを確認するこずもできたすここでは、型の特性、特にstd :: is_pointerも圹立ちたす。


8以前に倀を蚭定するために䜿甚されたものずは異なるナニオンフィヌルドを読み取ろうずしたずきの未定矩の動䜜



9long doubleの長さがバむナリモゞュヌル間で異なる堎合、範囲倖で読み取ろうずする可胜性がありたす



const int i0 = data->u.i[sizeof(long double) - 1U];


これはすでに前述したので、ここで前述の問題の別の存圚点を取埗したした。



解決策コンパむラヌが正しく凊理しおいるこずが確実でない限り、前に蚭定したフィヌルド以倖のフィヌルドを参照しないでください。共有オブゞェクトタむプのサむズが、盞互䜜甚するすべおのモゞュヌルで同じであるこずを確認しおください。



も参照しおください
Type-punning and strict-aliasing

What is the Strict Aliasing Rule and Why do we care?



10B.dllが正しくロヌドされ、「func」関数が正しく゚クスポヌトおよびむンポヌトされた堎合でも、この時点でB.dllはメモリからアンロヌドされたすFreeLibraryシステム関数は以前にDllMainコヌルバック関数のDLL_PROCESS_DETACHセクションで呌び出されおいたため 



auto data = func();


以前に砎棄されたポリモヌフィックタむプのオブゞェクトで仮想関数を呌び出すだけでなく、すでにアンロヌドされおいる動的ラむブラリで関数を呌び出すず、玔粋な仮想呌び出し゚ラヌが発生する可胜性がありたす。



解決策アプリケヌションに正しいファむナラむズ手順を実装しお、すべおのDLLが正しい順序で終了/アンロヌドされるようにしたす。避けに耇雑なロゞックで静的オブゞェクトを䜿甚しおDLラむブラリがそのラむフサむクルの最埌の段階に入る-その静的オブゞェクトを砎壊する盞のDllMain / DLL_PROCESS_DETACHを呌び出した埌、ラむブラリ内の任意の操䜜を実行L.は避けおください。



DLLのラむフサむクルを理解する必芁がありたす。



) LoadLibrary



  • ( , )
  • DllMain -> DLL_PROCESS_ATTACH ( , )
  • [] DllMain -> DLL_THREAD_ATTACH / DLL_THREAD_DETACH ( , . 30).
  • , , (, ),
  • ( / , , )
  • , ()
  • ( / , , )
  • - : ,


) FreeLibrary



  • DllMain -> DLL_PROCESS_DETACH ( , )
  • ( , )






11䞍透明なポむンタの削陀コンパむラはデストラクタを呌び出すために完党な型を知る必芁があるため、䞍透明なポむンタを䜿甚しおオブゞェクトを削陀するず、メモリリヌクやその他の問題が発生する可胜性がありたす



12DataNewデストラクタが仮想の堎合、クラスが正しく゚クスポヌトおよびむンポヌトされ、完党である堎合でもそれに関する情報は、ずにかくこの段階でそのデストラクタを呌び出すこずは問題です-これはおそらく玔粋に仮想の関数呌び出しに぀ながるでしょうDataNewタむプはすでにアンロヌドされたB.dllファむルからむンポヌトされるため。この問題は、デストラクタが仮想でない堎合でも発生する可胜性がありたす。



13DataNewクラスが抜象倚態性タむプの堎合、およびその基本クラスには、本䜓のない玔粋な仮想デストラクタがありたす。いずれの堎合も、玔粋な仮想関数呌び出しが発生したす。



14メモリがnewを䜿甚しお割り圓おられ、delete []を䜿甚しお削陀された堎合の未定矩の動䜜



delete[] data2;


䞀般に、倖郚モゞュヌルから取埗したオブゞェクトを解攟するずきは、垞に泚意する必芁がありたす。砎壊されたオブゞェクトぞのポむンタをれロにするこず



も良い習慣です。決定







  • オブゞェクトを削陀するずきは、その完党なタむプを知っおいる必芁がありたす
  • すべおの砎壊者は䜓を持っおいる必芁がありたす
  • コヌドの゚クスポヌト元のラむブラリを早めにアンロヌドしないでください
  • 垞に新しいフォヌムを䜿甚しお正しく削陀し、混同しないでください
  • リモヌトオブゞェクトぞのポむンタはれロにする必芁がありたす。






たた、次の点に泚意しおください

- voidぞのポむンタに削陀呌び出すずなり、未定矩の動䜜で

、玔粋仮想関数すべきではないコンストラクタから呌び出される

コンストラクタで仮想関数を呌び出す-ではありたせん仮想

-回避しようず手動メモリ管理を-䜿甚するコンテナ、移動セマンティクスを、そしおスマヌトポむンタヌ



も参照しおください
Heap corruption: What could the cause be?



15ExitThreadは、Cでスレッドを終了するための掚奚される方法です。C++では、この関数を呌び出すず、ロヌカルオブゞェクトのデストラクタおよびその他の自動クリヌンアップを呌び出す前にスレッドが終了するため、C ++でスレッドを終了するには、スレッド関数から戻るだけです。



ExitThread(0U);


解決策 C ++コヌドでこの関数を手動で䜿甚しないでください。



16DllMainの本䜓で、Kernel32.dll以倖のシステムDLLを必芁ずする暙準関数を呌び出すず、さたざたな蚺断が難しい問題が発生する可胜性がありたす。



CoInitializeEx(nullptr, COINIT_MULTITHREADED);


DllMainの゜リュヌション



  • 耇雑なde初期化を回避する
  • 他のラむブラリから関数を呌び出さないでくださいたたは少なくずもこれには非垞に泚意しおください






17マルチスレッド環境での疑䌌乱数ゞェネレヌタヌの誀った初期化



18time関数によっお返される時間の解像床は1秒であるため、この期間䞭にこの関数を呌び出すプログラム内のスレッドは、出力で同じ倀を受け取りたす。この番号を䜿甚しおPRNGを初期化するず、衝突が発生する可胜性がありたすたずえば、䞀時ファむルに同じ疑䌌ランダム名を生成したり、同じポヌト番号を生成したりするなど。考えられる解決策の1぀は、結果の結果を、ヒヌプ内のスタックたたはオブゞェクトのアドレス、より正確な時間などの疑䌌ランダム倀ず混合xorするこずです。



srand(time(nullptr));


解決策 MS VSでは、スレッドごずにPRNGの初期化が必芁です。さらに、初期化子ずしおUnix時間を䜿甚するず゚ントロピヌが䞍十分になるため、より高床な初期化倀の生成が掚奚されたす。



も参照しおください
Is there an alternative to using time to seed a random number generation?

C++ seeding surprises

Getting random numbers in a thread-safe way [C#]


19デッドロックたたはクラッシュする可胜性がありたすたたはDLLのロヌド順序で䟝存関係ルヌプが䜜成されたす



OTHER_LIB = LoadLibrary("B.dll");


解決策 DllMain゚ントリポむントでLoadLibraryを䜿甚しないでください。耇雑なde初期化は、「Init」や「Deint」などの特定のDLL開発者が゚クスポヌトした関数で実行する必芁がありたす。ラむブラリはこれらの関数をナヌザヌに提䟛し、ナヌザヌは適切なタむミングでそれらを正しく呌び出す必芁がありたす。䞡圓事者は、この契玄を厳守する必芁がありたす。







20タむプミス条件は垞にfalse、間違ったプログラムロゞック、およびリ゜ヌスリヌクの可胜性ダりンロヌドが成功したずきにOTHER_LIBがアンロヌドされないため



if (OTHER_LIB = nullptr)
    return FALSE;


コピヌによる割り圓お挔算子は、巊偎のタむプのリンクを返したす。ifはOTHER_LIB倀nullptrになりたすをチェックし、nullptrはfalseずしお解釈されたす。



解決策次のようなタむプミスを避けるために、垞に逆の圢匏を䜿甚しおください。



if/while (<constant> == <variable/expression>)


21_beginthreadシステム関数を䜿甚しおアプリケヌションに新しいスレッドを䜜成するこずをお勧めしたす特に、アプリケヌションが静的バヌゞョンのCランタむムラむブラリにリンクされおいる堎合。そうしないず、ExitThread、DisableThreadLibraryCallsを呌び出すずきにメモリリヌクが発生する可胜性がありたす。22



DllMainぞのすべおの倖郚呌び出しはシリアル化されるため、本文ではこの関数は、スレッド/プロセスを䜜成したり、それらず察話したりしないでください。そうしないず、デッドロックが発生する可胜性がありたす



CreateThread(nullptr, 0U, &Init, nullptr, 0U, nullptr);


23察応するコンポヌネントがすでにアンロヌドされおいる可胜性があるため、DLLの終了䞭にCOM関数を呌​​び出すず、誀ったメモリアクセスが発生する可胜性がありたす



CoUninitialize();


24むンプロセスCOM / OLEサヌビスのロヌドずアンロヌドの順序を制埡する方法がないため、DllMain関数からOleInitializeたたはOleUninitializeを呌び出さないでください。



OleUninitialize();


も参照しおください
COM Clients and Servers

In-process, Out-of-process, and Remote Servers



25新しい割り圓おられたメモリのブロックを解攟する



26アプリケヌションプロセスがその䜜業を終了するプロセスにある堎合lpvReservedパラメヌタのれロ以倖の倀で瀺される、珟圚のスレッドを陀くプロセス内のすべおのスレッドは、すでに終了しおいるか、次の堎合に匷制的に停止されおいたす。 ExitProcess関数を呌び出すず、ヒヌプなどの䞀郚のプロセスリ゜ヌスが䞍敎合な状態のたたになる可胜性がありたす。その結果、リ゜ヌスをクリヌンアップするこずはDLLセヌフではありたせん。代わりに、DLLはオペレヌティングシステムがメモリを再利甚できるようにする必芁がありたす。



free(INTEGERS);


解決策叀いCスタむルの手動メモリ割り圓おが「新しい」C ++スタむルず混圚しおいないこずを確認しおください。DllMain関数でリ゜ヌスを管理するずきは、现心の泚意を払っおください。



27システムが終了コヌドを実行した埌でも、DLLが䜿甚される可胜性がありたす



const BOOL result = FreeLibrary(OTHER_LIB);


解決策 DllMain゚ントリポむントでFreeLibraryを呌び出さないでください。 28珟圚のおそらくメむンのスレッドがクラッシュしたす







throw new std::runtime_error("    ");


解決策 DllMain関数で䟋倖をスロヌしないようにしたす。䜕らかの理由でDLLを正しくロヌドできない堎合、関数は単にFALSEを返す必芁がありたす。たた、DLL_PROCESS_DETACHセクションから䟋倖をスロヌしないでください。



DLLの倖郚で䟋倖をスロヌするずきは、垞に泚意しおください。耇雑なオブゞェクトたずえば、暙準ラむブラリのクラスは、ランタむムラむブラリの異なる互換性のないバヌゞョンでコンパむルされおいる堎合、異なる実行可胜モゞュヌルで異なる物理的衚珟および䜜業のロゞックを持぀こずができたす。







モゞュヌル間で単玔なデヌタタむプのみを亀換しおみおください固定サむズず明確に定矩されたバむナリ衚珟を䜿甚。



メむンスレッドを終了するず、他のすべおのスレッドが自動的に終了するこずに泚意しおください正しく終了しないため、メモリが損傷し、同期プリミティブやその他のオブゞェクトが予枬できない誀った状態になりたす。さらに、これらのスレッドは、次の時点ですでに存圚しなくなりたす。静的オブゞェクトは独自の分解を開始するため、静的オブゞェクトのデストラクタでスレッドが終了するのを埅たないでください。



も参照しおください
Top 20 C++ multithreading mistakes and how to avoid them



29ここではキャッチされない䟋倖たずえば、std :: bad_allocをスロヌできたす。



THREADS.push_back(std::this_thread::get_id());


DLL_THREAD_ATTACHセクションは䞍明な倖郚コヌドから呌び出されるため、ここで正しい動䜜が芋られるずは思わないでください。



解決策 try / catchコマンドを䜿甚しお、正しく凊理できない可胜性が最も高い䟋倖をスロヌする可胜性のあるステヌトメントを囲みたす特に、DLLから終了する堎合。



も参照しおください
How can I handle a destructor that fails?



30このDLLをロヌドする前にストリヌムが提瀺された堎合はUB



THREADS.pop_back();


既に存圚しおいるスレッド時にDLLが盎接ロヌドするこずも含め読み蟌たれるDLLはロヌドされお呌び出すこずはありたせんDLLの゚ントリポむント関数圌らはただDLL_THREAD_DETACHのむベントでそれを呌び出しおいる間、それらはDLL_THREAD_ATTACHむベント䞭THREADSベクタヌで登録されおいない理由です完了時に。

これは、DllMain関数のDLL_THREAD_ATTACHセクションずDLL_THREAD_DETACHセクションぞの呌び出しの数が異なるこずを意味したす。



31固定サむズの敎数型を䜿甚するこずをお勧めしたす



32異なるリンクおよびコンパむル蚭定ずフラグ異なるバヌゞョンのランタむムラむブラリなどでコンパむルするず、モゞュヌル間で耇雑なオブゞェクトを枡すずクラッシュする可胜性がありたす



ポむンタがこれらのモゞュヌルに異なる方法で凊理されおいる堎合、モゞュヌルによっお共有され、その仮想アドレスによっおオブゞェクトCぞのアクセス33が問題を匕き起こすこずができ、䟋えば、モゞュヌルは異なる関連付けられおいる堎合LARGEADDRESSAWAREのパラメヌタ



__declspec(dllexport) int Initialize(std::vector<int> integers, int& c) throw()


も参照しおください
Is it possible to use more than 2 Gbytes of memory in a 32-bit program launched in the 64-bit Windows?

Application with LARGEADDRESSAWARE flag set getting less virtual memory

Drawbacks of using /LARGEADDRESSAWARE for 32 bit Windows executables?

how to check if exe is set as LARGEADDRESSAWARE [C#]

/LARGEADDRESSAWARE [Ru]

ASLR (Address Space Layout Randomization) [Ru]



そしお...
Virtual memory

Physical Address Extension

Tagged pointer

std::ptrdiff_t

What is uintptr_t data type

Pointer arithmetic

Pointer aliasing

What is the strict aliasing rule?

reinterpret_cast conversion

restrict type qualifier



䞊蚘のリストはほずんど完党ではないので、おそらくコメントに重芁な䜕かを远加するこずができたす。



ポむンタの操䜜は、実際には、人々が通垞考えるよりもはるかに耇雑です。間違いなく、経隓豊富な開発者は、他の既存のニュアンスや埮劙な点を芚えるこずができたすたずえば、オブゞェクトぞのポむンタず関数ぞのポむンタの違いに぀いおの䜕か。そのため、おそらく、ポむンタのすべおのビットを䜿甚できるわけではありたせんなど。 。。







34関数内で䟋倖をスロヌできたす 



INTEGERS = new std::vector<int>(integers);


この関数のthrow指定は空です



__declspec(dllexport) int Initialize(std::vector<int> integers, int& c) throw()


std ::予期しないものは、䟋倖仕様に違反したずきにC ++ランタむムによっお呌び出されたす。䟋倖仕様がこのタむプの䟋倖を蚱可しない関数から、䟋倖がスロヌされたす。



解決策 try / catch特に、特にDLLでリ゜ヌスを割り圓おる堎合たたはnothrow圢匏のnew挔算子を䜿甚したす。いずれにせよ、さたざたな皮類のリ゜ヌスを割り圓おるすべおの詊みが垞に正垞に終了するずいう玠朎な仮定から始めないでください。



も参照しおください
RAII

We do not use C++ exceptions

Memory Limits for Windows and Windows Server Releases









問題1そのような「よりランダムな」倀の圢成は正しくありたせん。䞭倮限界定理によれば、独立したランダム倉数の合蚈は、均䞀な分垃ではなく、正芏の分垃になる傟向がありたす初期倀自䜓が均䞀に分垃しおいる堎合でも。



問題2敎数型のオヌバヌフロヌの可胜性笊号付き敎数型の未定矩の動䜜



return rand() + rand();


疑䌌乱数ゞェネレヌタや暗号化などを䜿甚する堎合は、垞に自家補の「゜リュヌション」の䜿甚に泚意しおください。これらの非垞に特殊な分野で専門的な教育ず経隓を持っおいない限り、単に自分を裏切っお状況を悪化させる可胜性は非垞に高いです。



35゚クスポヌトされた関数の名前はextern "C"の䜿甚を防ぐために装食倉曎されたす



36この呜名スタむルはSTL甚に予玄されおいるため、 '_'で始たる名前はC ++では暗黙的に犁止されおいたす



__declspec(dllexport) long long int __cdecl _GetInt(int a)


いく぀かの問題ずその可胜な解決策



37ランドがされお いないスレッドセヌフでは、䜿甚rand_rは、 /の代わりにrand_s



38ランドが、廃止されおより有効に掻甚珟代
C++11 <random>


39rand関数が珟圚のスレッド専甚に初期化されたずいう事実ではありたせんMS VSでは、呌び出されるスレッドごずにこの関数の初期化が必芁です



40疑䌌ランダム番号の特別なゞェネレヌタヌがあり、ハッキングに匷い゜リュヌションで䜿甚するこずをお勧めしたすこれらは適切ですLibsodium / randombytes_buf、OpenSSL / RAND_bytesなどのポヌタブル゜リュヌション



41れロによる朜圚的な陀算珟圚のスレッドを終了させる可胜性がありたす



42優先順䜍の異なる挔算子が同じ行で䜿甚されおいるため、蚈算の順序に混乱が生じたす-括匧を䜿甚し、 /たたはシヌケンスポむント明らかな蚈算順序を指定する



43朜圚的な敎数オヌバヌフロヌ



return 100 / a <= 0 ? a : a + 1 + Random();




も参照しおください
Do not use std::rand() for generating pseudorandom numbers





そしお...
ExitThread function

ExitProcess function

TerminateThread function

TerminateProcess function





そしお、それだけではありたせん



メモリに重芁なコンテンツナヌザヌのパスワヌドなどがあるず想像しおください。もちろん、実際に必芁な時間より長くメモリに保持したくないので、誰かがそこから読み取る可胜性が高くなりたす。



この問題を解決するための玠朎なアプロヌチは、次のようになりたす。



bool login(char* const userNameBuf, const size_t userNameBufSize,
           char* const pwdBuf, const size_t pwdBufSize) throw()
{
    if (nullptr == userNameBuf || '\0' == *userNameBuf || nullptr == pwdBuf)
        return false;
    
    // Here some actual implementation, which does not checks params
    //  nor does it care of the 'userNameBuf' or 'pwdBuf' lifetime,
    //   while both of them obviously contains private information 
    const bool result = doLoginInternall(userNameBuf, pwdBuf);
    
    // We want to minimize the time this private information is stored within the memory
    memset(userNameBuf, 0, userNameBufSize);
    memset(pwdBuf, 0, pwdBufSize);
}


そしお、それは確かに私たちが望むようには機胜したせん。それでは䜕をすべきでしょうか:(



間違った「解決策」1memsetが機胜しない堎合は、手動で実行したしょう



void clearMemory(char* const memBuf, const size_t memBufSize) throw()
{
    if (!memBuf || memBufSize < 1U)
        return;
    
    for (size_t idx = 0U; idx < memBufSize; ++idx)
        memBuf[idx] = '\0';
}


なぜこれも私たちに合わないのですか事実、このコヌドには、最新のコンパむラが最適化できないような制限はありたせんちなみに、memset関数がただ䜿甚されおいる堎合は、おそらく組み蟌みになりたす。



も参照しおください
The as-if rule

Are there situations where this rule does not apply?

Copy elision

Atomics and optimization



間違った「解決策」2volatileキヌワヌドをいじっお、前の「解決策」を「改善」しようずする



void clearMemory(volatile char* const volatile memBuf, const volatile size_t memBufSize) throw()
{
    if (!memBuf || memBufSize < 1U)
        return;
    
    for (volatile size_t idx = 0U; idx < memBufSize; ++idx)
        memBuf[idx] = '\0';
    
    *(volatile char*)memBuf = *(volatile char*)memBuf;
    // There is also possibility for someone to remove this "useless" code in the future
}


これは機胜したすか倚分。たずえば、このアプロヌチはRtlSecureZeroMemoryで䜿甚されたすWindows SDK゜ヌスでこの関数の実際の実装を確認するこずで自分で確認できたす。



ただし、この手法はすべおのコンパむラで期埅どおりに機胜するずは限りたせん。



も参照しおください
volatile member functions



間違った「解決策」3䞍適切なOS API関数䟋RtlZeroMemoryたたはSTL䟋std :: fill、std :: for_eachを䜿甚する



RtlZeroMemory(memBuf, memBufSize);


この問題を解決する詊みの他の䟋はここにありたす。



そしお、それはどのように正しいのですか



  • 正しい䜿甚OSのAPIの機胜を䟋えば、RtlSecureZeroMemoryのために、Windowsの
  • 利甚機胜C11の memset_s


さらに、倉数の倀をファむル、コン゜ヌル、たたはその他のストリヌムに出力するこずで、コンパむラヌがコヌドを最適化するのを防ぐこずができたすが、これは明らかにあたり圹に立ちたせん。



も参照しおください
Safe clearing of private Data



たずめ



もちろん、これは、C / C ++でアプリケヌションを䜜成するずきに発生する可胜性のあるすべおの問題、ニュアンス、および埮劙な点の完党なリストではありたせん。



次のような玠晎らしいものもありたす。



  • ラむブロック;
  • (, , ABA, , );
  • ;
  • (- , , );
  • GDI ;
  • , volatile atomic ;
  • (, 0603 603);
  • チェック/アクセスの非同期化の問題チェック時間から䜿甚時間;
  • 参照されるオブゞェクトよりも長生きするラムダ匏。
  • printfファミリヌの機胜での誀ったフォヌマット仕様の䜿甚;
  • バむトオヌダヌが異なる2぀のデバむス間たずえば、ネットワヌク経由でのデヌタの誀った亀換など。


そしお、はるかに。







远加するものはありたすかコメントであなたの興味深い経隓を共有しおください



PSもっず知りたいですか
Software security errors

Common weakness enumeration

Common types of software vulnerabilities



Vulnerability database

Vulnerability notes database

National vulnerability database



Coding standards

Application security verification standard

Guidelines for the use of the C++ language in critical systems



Secure programming HOWTO

32 OpenMP Traps For C++ Developers

A Collection of Examples of 64-bit Errors in Real Programs




All Articles