لماذا يؤدي strcpy إلى حدوث خطأ تجزئة مع المتغيرات العالمية؟

StackOverflow https://stackoverflow.com/questions/122877

سؤال

إذن لدي بعض رموز 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() لتجنب تجاوزات المخزن المؤقت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top