لماذا يؤدي strcpy إلى حدوث خطأ تجزئة مع المتغيرات العالمية؟
-
02-07-2019 - |
سؤال
إذن لدي بعض رموز C:
#include <stdio.h>
#include <string.h>
/* putting one of the "char*"s here causes a segfault */
void main() {
char* path = "/temp";
char* temp;
strcpy(temp, path);
}
يقوم هذا بتجميع وتشغيل والتصرف كما يبدو.ومع ذلك، إذا تم تعريف أحد مؤشرات الأحرف أو كليهما كمتغير عام، فإن strcpy يؤدي إلى خطأ تجزئة.لماذا يحدث هذا؟من الواضح أن هناك خطأ في فهمي للنطاق.
المحلول
كما ذكرت ملصقات أخرى، فإن أصل المشكلة هو أن درجة الحرارة غير مهيأة.عندما يتم الإعلان عنه كمتغير تلقائي على المكدس، فإنه سيحتوي على أي شيء غير مرغوب فيه موجود في موقع الذاكرة هذا.على ما يبدو بالنسبة للمترجم + وحدة المعالجة المركزية + نظام التشغيل الذي تقوم بتشغيله، فإن البيانات المهملة الموجودة في هذا الموقع هي مؤشر صالح."ينجح" strcpy من حيث أنه لا يقسم، ولكنه في الواقع ينسخ سلسلة إلى موقع عشوائي في مكان آخر في الذاكرة.هذا النوع من مشاكل تلف الذاكرة يبث الخوف في قلوب مبرمجي لغة C في كل مكان حيث يصعب تصحيح الأخطاء بشكل غير عادي.
عند نقل إعلان المتغير المؤقت إلى النطاق العام، يتم وضعه في قسم BSS ويتم تصفيره تلقائيًا.تؤدي محاولات إلغاء الإشارة إلى *درجة الحرارة إلى حدوث خطأ segfault.
عندما تقوم بنقل *path إلى النطاق العام، فإن *temp يتحرك لأعلى موقع واحد على المكدس.من الواضح أن البيانات المهملة الموجودة في هذا الموقع ليست مؤشرًا صالحًا، وبالتالي يؤدي إلغاء الإشارة إلى *temp إلى حدوث خطأ segfault.
نصائح أخرى
لا يشير المتغير المؤقت إلى أي مساحة تخزين (ذاكرة) وهو غير مهيأ.
إذا تم الإعلان عن درجة الحرارة char temp[32];
عندها سيعمل الكود بغض النظر عن مكان الإعلان عنه.ومع ذلك، هناك مشاكل أخرى في الإعلان عن درجة الحرارة بحجم ثابت مثل هذا، ولكن هذا سؤال ليوم آخر.
الآن، لماذا يتعطل عندما يتم الإعلان عنه عالميًا وليس محليًا.حظ...
عندما يتم الإعلان عنها محليًا، فإن قيمة درجة الحرارة تأتي من أي قيمة قد تكون موجودة على المكدس في ذلك الوقت.ومن حسن الحظ أنه يشير إلى عنوان لا يتسبب في حدوث عطل.ومع ذلك، فهو يدمر الذاكرة التي يستخدمها شخص آخر.
عند الإعلان عنها عالميًا، سيتم تخزين هذه المتغيرات في معظم المعالجات في مقاطع البيانات التي ستستخدم صفحات صفرية الطلب.هكذا char *temp
يبدو كما لو تم الإعلان عنه char *temp=0
.
لقد نسيت تخصيص وتهيئة درجة الحرارة:
temp = (char *)malloc(TEMP_SIZE);
فقط تأكد من أن TEMP_SIZE كبير بما يكفي.يمكنك أيضًا حساب ذلك في وقت التشغيل، ثم التأكد من أن الحجم كافٍ (يجب أن يكون على الأقل strlen(path))
كما ذكرنا أعلاه، لقد نسيت تخصيص مساحة لدرجة الحرارة.أنا أفضل strdup
ل malloc+strcpy
.يفعل ما تريد القيام به.
لا - هذا لا يعمل بغض النظر عن المتغيرات - يبدو أنه حدث لأنك (غير) محظوظ.تحتاج إلى تخصيص مساحة لتخزين محتويات السلسلة، بدلاً من ترك المتغير غير مهيأ.
ستشير المتغيرات غير المهيأة الموجودة على المكدس إلى مواقع عشوائية إلى حد كبير في الذاكرة.إذا كانت هذه العناوين صالحة، فسوف تدوس التعليمات البرمجية الخاصة بك على كل ما كان موجودًا، ولكنك لن تحصل على خطأ (ولكن قد تحصل على أخطاء سيئة تتعلق بتلف الذاكرة في مكان آخر في التعليمات البرمجية الخاصة بك).
تفشل العناصر العالمية باستمرار لأنها عادةً ما يتم ضبطها على أنماط محددة تشير إلى ذاكرة غير معينة.تمنحك محاولة إلغاء الإشارة إلى خطأ segfault على الفور (وهذا أفضل - تركه لاحقًا يجعل من الصعب جدًا تعقب الخطأ).
أود إعادة كتابة جزء آدم أولاً كـ
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, sizeof(temp), path);
temp[sizeof(temp)-1] = '\0';
بهذه الطريقة أنت:
1. don't have magic numbers laced through the code, and
2. you guarantee that your string is null terminated.
النقطة الثانية هي فقدان الحرف الأخير من السلسلة المصدر إذا كان طوله أكبر من = 256 حرفًا.
الجزء المهم الذي يجب ملاحظته:
يجب أن تكون سلسلة الوجهة كبيرة بما يكفي لتلقي النسخة.
في حالتك، لا تحتوي درجة الحرارة على ذاكرة مخصصة للنسخ إليها.
تم النسخ من صفحة الدليل الخاصة بـ strcpy :
DESCRIPTION
The strcpy() function copies the string pointed to by src (including
the terminating '\0' character) to the array pointed to by dest. The
strings may not overlap, and the destination string dest must be large
enough to receive the copy.
أنت تستدعي سلوكًا غير محدد، نظرًا لأنك لا تقوم بتهيئة temp
عامل.إنه يشير إلى موقع عشوائي في الذاكرة، لذا فإن برنامجك يمكن العمل، ولكن على الأرجح أنه سوف segfault.يجب أن تكون السلسلة الوجهة عبارة عن مصفوفة، أو أن تشير إلى الذاكرة الديناميكية:
// Make temp a static array of 256 chars
char temp[256];
strncpy(temp, 256, path);
// Or, use dynamic memory
char *temp = (char *)malloc(256);
strncpy(temp, 256, path);
أيضا استخدام strncpy()
بدلاً من strcpy()
لتجنب تجاوزات المخزن المؤقت.