PRB: التابعة ترث المقابض غير مقصودة أثناء استدعاء CreateProcess

الأعراض

عندما تقوم بإنشاء عملية تابعة باستخدام الدالة CreateProcess الاتصال في بيئة ذات مؤشرات ترابط متعددة، قد يرث الطفل مقابض لا يقصد أن تكون موروثة.

السبب

يمكن أن يحدث هذا السلوك إذا كان اثنين من مؤشرات الترابط في نفس الوقت إنشاء العمليات التابعة وإعادة توجيه مقابض الانحراف عن طريق الأنابيب. في هذا السيناريو، هناك حالة تعارض أثناء إنشاء أنابيب والعمليات التي من الممكن أن ترث مؤشرات الملفات التابعة الأخرى بغرض طفل واحد. إنشاء مؤشر ترابط واحد الأنابيب، وبينما يكون مؤشر الترابط في عملية إنشاء العملية، الصفحات الأخرى أيضا إنشاء عملية تابعة. تتكرر عبر كافة مؤشرات قابلة للتوريث في التطبيق أثناء استدعاء CreateProcess إلى العملية التابعة.

الحل

للتغلب على هذه المشكلة، التفاف التعليمة البرمجية إنشاء طفل في مقطع حرج. وهذا يمنع أي توريث غير المقصودة. لهذا الأسلوب للعمل بشكل صحيح، قم بإنشاء التوجيهات نونينهيريتابل بتعيين واصف الأمان إلى قيمة خالية. ثم قم بتعيين أطراف الإخراج الذي تريده التابعة ترث كانتشار باستخدام استدعاء دالة سيثاندلينفورميشن ، كما هو موضح في نموذج التعليمات البرمجية التالية:

CRITICAL_SECTION    cs;HANDLE              hReadIn, hWriteIn;
HANDLE hReadOut, hWriteOut;
HANDLE hReadErr, hWriteErr;

InitializeCriticalSection(&cs);

EnterCriticalSection(&cs);

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) )
{
// an error occurred
}

if ( !SetHandleInformation(hReadIn, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

if ( !SetHandleInformation(hWriteOut, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

if ( !SetHandleInformation(hWriteErr, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) )
{
// an error occurred
}

STARTUP_INFO si;
PROCESS_INFORMATION pi;

si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hReadIn;
si.hStdOutput = hWriteOut;
si.hStdError = hWriteErr;

if ( !CreateProcess( "child.exe",
NULL,
NULL, NULL,
TRUE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

CloseHandle(hReadIn);
CloseHandle(hWriteOut);
CloseHandle(hWriteErr);

LeaveCriticalSection(&cs);

لاحظ أن لا يأتي الحل السابق دون تكاليف. إنشاء المقاطع الحرجة في التعليمات البرمجية في بعض الأحيان فوضوي ويأتي بسعر منخفض الأداء. هناك حل آخر لهذه المشكلة، وأنه يتطلب إنشاء تطبيق الوسيطة لتشغيل الطفل. ومع ذلك، يحتوي هذا الحل أيضا الجانب السلبي. العيب الرئيسي لهذا الأسلوب هو يفقد الأصل أساسا السهولة التي تحصل عليها معرف العملية. الطفل إذا أحتاج الأصل معرف العملية، العملية المتوسطة يجب تمريره مرة أخرى على نحو ما.

باستخدام هذا الأسلوب تطبيق متوسط، تجنب أي توريث عرضي بالاعتماد على Windows للقيام بالأعمال نيابة عنك. أي مؤشر الموروثة عن طريق الخطأ في العملية المتوسطة سيتم بالتأكيد عدم تكرار عبر للطفل. هذا يضمن إذا حددت للمعلمة بينهيريثاندليس في استدعاء CreateProcess في تطبيق الوسيطة FALSE. سيتم تكرار مقابض التوجيه الخاص بك لا يزال سبب Windows دائماً بتكرار المؤشرات القياسية، حتى عندما يتم تعيين بينهيريثاندليس إلى FALSE.

التطبيق الأصلي

HANDLE              hReadIn, hWriteIn;HANDLE              hReadOut, hWriteOut;
HANDLE hReadErr, hWriteErr;

if ( !CreatePipe(&hReadIn, &hWriteIn, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadOut, &hWriteOut, NULL, 0) )
{
// an error occurred
}

if ( !CreatePipe(&hReadErr, &hWriteErr, NULL, 0) )
{
// an error occurred
}

STARTUP_INFO si;
PROCESS_INFORMATION pi;

si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdInput = hReadIn;
si.hStdOutput = hWriteOut;
si.hStdError = hWriteErr;

if ( !CreateProcess( "Intermediate.exe",
NULL,
NULL, NULL,
TRUE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

CloseHandle(hReadIn);
CloseHandle(hWriteOut);
CloseHandle(hWriteErr);


تطبيق متوسط

STARTUP_INFO        si;PROCESS_INFORMATION pi;

si.cb = sizeof(si);

if ( !CreateProcess( "child.exe",
NULL,
NULL, NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
lpEnvironment,
&si, &pi) )
{
// an error occurred
}

خصائص

رقم الموضوع: 315939 - آخر مراجعة: 19‏/01‏/2017 - المراجعة: 1

تعليقات