হ্যাঁ, __attribute__((packed))
কিছু সিস্টেমে সম্ভাব্য অনিরাপদ। লক্ষণটি সম্ভবত কোনও x86-এ প্রদর্শিত হবে না, যা সমস্যাটিকে আরও কুখ্যাত করে তোলে; x86 সিস্টেমে পরীক্ষা করা সমস্যা প্রকাশ করবে না। (X86-তে, ভুলভাবে স্বাক্ষরিত অ্যাক্সেসগুলি হার্ডওয়ারে পরিচালনা করা হয়;int*
পয়েন্টারটিকে কোনও নির্দিষ্ট ঠিকানা নির্দেশ করে তবে এটি সঠিকভাবে সংযুক্ত থাকলে কিছুটা ধীর হবে তবে আপনি সঠিক ফলাফল পাবেন))
কিছু অন্যান্য সিস্টেমে যেমন স্পার্ক, একটি বিভ্রান্তিকৃত int
বস্তু অ্যাক্সেস করার চেষ্টা করার ফলে প্রোগ্রামটি ক্র্যাশ হয়ে একটি বাস ত্রুটির সৃষ্টি করে।
এমন সিস্টেমগুলিও রয়েছে যেখানে একটি বিভ্রান্তিকৃত অ্যাক্সেস চুপচাপভাবে ঠিকানার নীচের অর্ডারের বিটগুলিকে উপেক্ষা করে, যার ফলে এটি মেমরির ভুল অংশে অ্যাক্সেস করে।
নিম্নলিখিত প্রোগ্রাম বিবেচনা করুন:
#include <stdio.h>
#include <stddef.h>
int main(void)
{
struct foo {
char c;
int x;
} __attribute__((packed));
struct foo arr[2] = { { 'a', 10 }, {'b', 20 } };
int *p0 = &arr[0].x;
int *p1 = &arr[1].x;
printf("sizeof(struct foo) = %d\n", (int)sizeof(struct foo));
printf("offsetof(struct foo, c) = %d\n", (int)offsetof(struct foo, c));
printf("offsetof(struct foo, x) = %d\n", (int)offsetof(struct foo, x));
printf("arr[0].x = %d\n", arr[0].x);
printf("arr[1].x = %d\n", arr[1].x);
printf("p0 = %p\n", (void*)p0);
printf("p1 = %p\n", (void*)p1);
printf("*p0 = %d\n", *p0);
printf("*p1 = %d\n", *p1);
return 0;
}
জিসিসি 4.5.2 সহ এক্স 86 উবুন্টুতে, এটি নিম্নলিখিত আউটপুট উত্পাদন করে:
sizeof(struct foo) = 5
offsetof(struct foo, c) = 0
offsetof(struct foo, x) = 1
arr[0].x = 10
arr[1].x = 20
p0 = 0xbffc104f
p1 = 0xbffc1054
*p0 = 10
*p1 = 20
জিপিসি 4.5.1 সহ স্পার্ক সোলারিস 9 এ এটি নিম্নলিখিত উত্পাদন করে:
sizeof(struct foo) = 5
offsetof(struct foo, c) = 0
offsetof(struct foo, x) = 1
arr[0].x = 10
arr[1].x = 20
p0 = ffbff317
p1 = ffbff31c
Bus error
উভয় ক্ষেত্রেই, প্রোগ্রামটি কোনও অতিরিক্ত বিকল্প ছাড়াই সংকলিত হয়েছে, ঠিক নেই gcc packed.c -o packed
।
(একটি প্রোগ্রাম যা অ্যারের পরিবর্তে একটি একক কাঠামো ব্যবহার করে নির্ভরযোগ্যভাবে সমস্যাটি প্রদর্শন করে না, যেহেতু সংকলকটি কাঠামোটটিকে একটি বিজোড় ঠিকানায় বরাদ্দ করতে পারে যাতে x
সদস্যটি সঠিকভাবে সংযুক্ত থাকে। দুটি struct foo
অবজেক্টের অ্যারে সহ , কমপক্ষে একটি বা অন্যটি একটি বিভ্রান্ত x
সদস্য থাকবে।)
(এই ক্ষেত্রে, p0
একটি শ্রেণীবদ্ধ ঠিকানায় পয়েন্ট, কারণ এটি একটি বস্তাবন্দী স্থানটিকে int
একটি নিম্নলিখিত সদস্য char
সদস্য। p1
সঠিকভাবে প্রান্তিককৃত করতে হবে, যেহেতু এটি অ্যারের দ্বিতীয় উপাদান একই সদস্যের কাছে পয়েন্ট ঘটবে, তাই দুটি char
এটা পূর্ববর্তী বস্তু - এবং SPARC সোলারিস এ অ্যারেarr
এমন একটি ঠিকানায় বরাদ্দ করা হয়েছে যা 4 এর একাধিক নয়))
নামের দ্বারা x
কোনও সদস্যকে উল্লেখ করার সময় struct foo
, সংকলকটি জানে যে x
এটি সম্ভাব্যভাবে বিভ্রান্ত হয়েছে এবং এটি সঠিকভাবে অ্যাক্সেস করার জন্য অতিরিক্ত কোড তৈরি করবে।
একবার কোনও পয়েন্টার অবজেক্টে ঠিকানা arr[0].x
বা arr[1].x
সংরক্ষণ করা হয়ে গেলে , সংকলক বা চলমান প্রোগ্রামটি কেউই জানে না যে এটি একটি বিভ্রান্তিকর int
বস্তুটিকে নির্দেশ করে। এটি কেবল ধরে নিয়েছে যে এটি যথাযথভাবে সংযুক্ত রয়েছে, যার ফলে (কিছু সিস্টেমে) একটি বাস ত্রুটি বা অন্যান্য অনুরূপ ব্যর্থতা রয়েছে।
জিসিসিতে এটি স্থির করা, আমার বিশ্বাস, অযৌক্তিক হবে। একটি সাধারণ সমাধানের প্রয়োজন হবে, প্রতিটি ত্রুটিযুক্ত অ্যালাইনমেন্ট প্রয়োজনীয়তার সাথে যে কোনও ধরণের পয়েন্টারকে ডিফারেন্স করার চেষ্টা করা হয় (ক) সংকলনের সময় প্রমাণ করে যে পয়েন্টারটি কোনও প্যাকড স্ট্রাক্টের বিভ্রান্ত সদস্যকে নির্দেশ না করে, বা (খ) বাল্কিয়ার এবং স্লো কোড উত্পন্ন করে যা প্রান্তিক বা মিস্যালাইনযুক্ত বস্তুগুলি পরিচালনা করতে পারে।
আমি একটি জিসিসি বাগ রিপোর্ট জমা দিয়েছি । যেমনটি আমি বলেছি, আমি বিশ্বাস করি না এটি ঠিক করা এটি ব্যবহারিক, তবে ডকুমেন্টেশনের মধ্যে এটি উল্লেখ করা উচিত (এটি বর্তমানে তা নয়)।
আপডেট : 2018-12-20 হিসাবে, এই বাগটি ফিক্সড হিসাবে চিহ্নিত করা হয়েছে। প্যাচটি জিসিসি 9 তে একটি নতুন -Waddress-of-packed-member
বিকল্প সংযোজন সহ ডিফল্টরূপে সক্ষম হবে।
যখন স্ট্রাক্ট বা ইউনিয়নের প্যাকড সদস্যের ঠিকানা নেওয়া হয়, এটি একটি স্বাক্ষরবিহীন পয়েন্টার মান হতে পারে। এই প্যাচটি পয়েন্টার অ্যাসাইনমেন্টে সারিবদ্ধতা পরীক্ষা করতে এবং স্বাক্ষরবিহীন ঠিকানার পাশাপাশি অ-স্বাক্ষরিত পয়েন্টারটি সতর্ক করতে -ড্রেস-অফ-প্যাক-সদস্য যোগ করে
আমি উত্স থেকে সিসিটি সংস্করণটি তৈরি করেছি। উপরের প্রোগ্রামটির জন্য, এটি এই ডায়াগোনস্টিকগুলি উত্পাদন করে:
c.c: In function ‘main’:
c.c:10:15: warning: taking address of packed member of ‘struct foo’ may result in an unaligned pointer value [-Waddress-of-packed-member]
10 | int *p0 = &arr[0].x;
| ^~~~~~~~~
c.c:11:15: warning: taking address of packed member of ‘struct foo’ may result in an unaligned pointer value [-Waddress-of-packed-member]
11 | int *p1 = &arr[1].x;
| ^~~~~~~~~