كيفية إصلاح فساد الكومة
-
21-09-2019 - |
سؤال
لقد حاولت بناء مكتبة قراءة ذاكرة للغاية لقراءة بعض unsigned int
S خارجها. ومع ذلك ، واجهت رسالة خطأ "الكشف المكتشف" عندما تكون ReadUnsignedInt
الطريقة تريد العودة.
اكتشاف فساد كومة. اكتشف CRT أن التطبيق كتب إلى الذاكرة بعد نهاية المخزن المؤقت.
كما قرأت ، قد يكون هذا هو السبب عند محاولة حذف شيء ما. قد يكون هذا سبب بعض الاستخدام غير الصحيح لـ std::tr1::shared_ptr
لكن لا يمكنني تحديد ما أفعله خطأ معهم. الكود كما يلي (تم حذف معالجة الأخطاء):
unsigned int Memory::ReadUnsignedInt (unsigned int address) const {
std::tr1::shared_ptr<byte> bytes =
this->ReadBytes(address, sizeof(unsigned int));
return *((int*)bytes.get());
// correct value (how to improve this ugly piece of code?)
}
std::tr1::shared_ptr<byte> Memory::ReadBytes (
unsigned int address, int numberOfBytes) const
{
std::tr1::shared_ptr<byte> pBuffer(new byte(numberOfBytes));
ReadProcessMemory(m_hProcess.get(), (LPCVOID)address,
pBuffer.get(), numberOfBytes * sizeof(byte), NULL))
return pBuffer;
}
المحلول
وجد كل من مايكل ونافين نفس العيب الرئيسي في الكود الخاص بك ، ولكن ليس العيب الوحيد.
shared_ptr
إرادة delete
كائن مدبب AT عندما يذهب عدد المرجع إلى الصفر.
هذا يعني أنه يمكنك فقط إعطائها كائنات مخصصة من قبل new
-- ليس new[]
.
قد ترغب في استخدام shared_ptr<vector<byte> >
أو boost::shared_array<byte>
في حين أن.
نصائح أخرى
والقضية هي:
new byte(numberOfBytes)
هذا يخصص بايت واحد مع قيمة numberOfbytes.
تريد ان تفعل:
new byte[numberOfBytes]
الذي يخصص مجموعة من bytes numberofbytes طويلة.
ولكن بما أنك تعلم أنك تقرأ فقط 4 بايت ، فلماذا تهتم بتخصيص الذاكرة على الإطلاق؟ فقط تمرير عنوان int غير موقعة على المكدس.
تمت الإشارة إلى المشكلات الأساسية في الكود الخاص بك بالفعل. بالنظر إلى ذلك ، تركت أتساءل عن سبب استخدامك لـ shared_ptr هنا على الإطلاق. إذا كنت أفعل ذلك ، فربما أستخدم شيئًا كهذا:
unsigned Memory::ReadUnsignedInt(unsigned address) {
unsigned ret;
ReadProcessMemory(m_hProcess.get(), (void *)address, &ret, sizeof(ret), NULL);
return ret;
}
std::vector<char> Memory::ReadBytes(unsigned address, int num) {
std::vector<char> ret(num);
ReadProcessMemory(m_hProcess.get(), (void *)address, &ret[0], num, NULL);
return ret;
}
ثم مرة أخرى ، بدلاً من ReadUnsignedInt ، سأغري استخدام قالب:
template <class T>
T Memory::Read(unsigned address) {
T ret;
ReadProcessMemory(m_hProcess.get(), (void*)address, &ret, sizeof(ret), NULL);
return ret;
}
نظرًا لأنك لا تمرر معلمة يمكنها من خلالها استنتاج النوع لمعلمة القالب ، يجب عليك دائمًا تحديد صراحة:
int x = Read<int>(wherever);
char a = Read<char>(wherever);
سيكون البديل هو تمرير الوجهة كمعلمة:
template <class T>
Memory::Read(unsigned address, T &t) {
ReadProcessMemory(my_hProcess.get(), (void *)address, &t, sizeof(t), NULL);
};
ما الذي تستخدمه مثل:
Read(wherever, some_int);
Read(somewhere, some_long);
وهلم جرا.
إذا كنت قلقًا بشأن عدم كفاءة إرجاع ناقل char ، فمن المحتمل ألا يكون ذلك - VC ++ (مثل معظم المترجمين الحاليين المعقولين) لديه ما يسمى "تحسين قيمة الإرجاع المسماة" ، مما يعني في مثل هذا الموقف ، ، إنه يمرر مرجعًا خفيًا إلى المتجه الذي تقوم بتعيينه للنتيجة ، وسوف تستخدم ReadBytes ذلك لإيداع البيانات مباشرة حيث سينتهي الأمر على أي حال. لهذه المسألة ، مع تشغيل أي تحسين معقول على الإطلاق ، سينتهي ReadBytes تقريبًا كدالة مضمونة ، لذلك لا يتم إرجاع أي شيء متورط حقًا أو "يتم إرجاعه" على الإطلاق.
من ناحية أخرى ، لن يعمل هذا الرمز بشكل جيد بشكل خاص مع المترجمين الأكبر سناً - ومع المترجمين القدامى بما فيه الكفاية ، فإن الإصدارات التي تستخدم وظائف قالب الأعضاء ربما لن يتم تجميعها. طالما أنك تستخدم برنامج التحويل البرمجي الحالي بشكل معقول ، يجب أن تكون الحياة جيدة.
أعتقد new byte(numberOfBytes)
يجب ان يكون new byte[numberOfBytes]
. وإلا فإنك قد خصصت بايت واحد فقط. فقط لإكمال الإجابة ، كما أشار ephemient أنه لا يمكنك استخدام shared_ptr هنا لأنها ستفعل delete
حيث يجب أن تفعل delete[]
. إذا لم يتم القيام بذلك ، فلن يكون السلوك غير محدد.