বর্ধিত জিসিসি 6 অপ্টিমাইজার ব্যবহারিক সি ++ কোডটি কেন ভাঙবে?


148

জিসিসি এর একটি নতুন অপ্টিমাইজার বৈশিষ্ট্য রয়েছে : এটি ধরে নেওয়া হয় যে thisসর্বদা বাতিল হয় না এবং এর ভিত্তিতে অনুকূলিত হয়।

মান পরিসীমা প্রচার এখন ধরে নেওয়া হয়েছে যে সি ++ সদস্য ফাংশনের এই পয়েন্টারটি নাল নয়। এটি সাধারণ নাল পয়েন্টার চেকগুলি সরিয়ে দেয় তবে কিছু অ-অনুসারী কোড-বেসগুলিকেও ভেঙে দেয় (যেমন Qt-5, ক্রোমিয়াম, কেডেভলফ) । অস্থায়ী কাজ হিসাবে প্রায় -Fno-মুছা-নাল-পয়েন্টার-চেক ব্যবহার করা যেতে পারে। -ফ্যাসানাইটিজ = অপরিজ্ঞাত ব্যবহার করে ভুল কোড চিহ্নিত করা যায়।

পরিবর্তন দস্তাবেজটি স্পষ্টতই এটি বিপজ্জনক হিসাবে আখ্যায়িত করে কারণ এটি প্রায়শই ব্যবহৃত কোডের একটি বিস্ময়কর পরিমাণ ভঙ্গ করে।

এই নতুন অনুমানটি ব্যবহারিক সি ++ কোডটি কেন ভেঙে দেবে? এমন কোনও নিদর্শন রয়েছে যেখানে অযত্ন বা অজানা প্রোগ্রামাররা এই নির্দিষ্ট অপরিজ্ঞাত আচরণের উপর নির্ভর করে? আমি কারও লেখার কল্পনাও করতে পারি না if (this == NULL)কারণ এটি এতটাই অপ্রাকৃত।


21
@ বেন আশা করি আপনি এটি একটি ভাল উপায়ে বলতে চাইছেন। ইউবির সাথে কোডটি আবার লিখতে হবে যাতে ইউবি না ডাকে। এটা ঐটার মতই সহজ. হেক, প্রায়শই প্রায়শই জিজ্ঞাসিত প্রশ্নাগুলি থাকে যা আপনাকে এটি কীভাবে অর্জন করতে হয় তা বলে। সুতরাং, আসল সমস্যা নয় আইএমএইচও। সব ভালো.
মনিকা 15

49
কোডগুলিতে লোকেদের ডিফারেন্সিং রক্ষা করতে দেখে আমি অবাক হয়েছি। স্বাভাবিকভাবেই সুন্দর.
সের্গেইএ

19
@ বেন, অপরিজ্ঞাত আচরণটি প্রকাশের বিষয়টি খুব দীর্ঘ সময়ের জন্য অত্যন্ত কার্যকর অপ্টিমাইজেশনের কৌশল। আমি এটি পছন্দ করি, কারণ আমি অপ্টিমাইজেশন পছন্দ করি যা আমার কোডটি দ্রুত চালিত করে।
সের্গেইএ

17
আমি সের্গেইএএর সাথে একমত পুরো ব্রাউহাহা শুরু হয়েছিল কারণ লোকেরা মনে হয় যে এই বিষয়টিকে মনে করে যে thisএটি একটি অন্তর্নিহিত পরামিতি হিসাবে গৃহীত হয়েছে, তাই তারা তখন এটি একেবারে সুস্পষ্ট পরামিতি হিসাবে ব্যবহার করা শুরু করে। এটা না। আপনি যখন কোনও শূন্য বিষয়টিকে অবলম্বন করেন, আপনি ইউবিটিকে ঠিক তেমনভাবে অনুরোধ করছেন যেন আপনি অন্য কোনও নাল পয়েন্টারকে অবজ্ঞা করেন। এটুকুই আছে। আপনি যদি নাল্পটারগুলি চারপাশে পাস করতে চান তবে একটি সুস্পষ্ট প্যারামিটার, DUH ব্যবহার করুন । এটি কোনও ধীর গতির হবে না, এটি কোনও আঠালো হবে না এবং যেমন এপিআই রয়েছে এমন কোডটি অভ্যন্তরীণ অঞ্চলে যেভাবেই গভীর, তাই খুব সীমিত সুযোগ রয়েছে। গল্পের শেষে আমার মনে হয়।
মনিকা 19

41
খারাপ কোড -> খারাপ কোড সমর্থন করার জন্য অদক্ষ সংকলক -> আরও খারাপ কোড -> আরও অদক্ষ সংকলন -> ...
এমএম

উত্তর:


87

আমি মনে করি যে প্রশ্নের উত্তরের উত্তর দেওয়া দরকার কেন সচ্ছল লোকেরা প্রথমে চেকগুলি লিখবে।

সর্বাধিক সাধারণ ক্ষেত্রে সম্ভবত যদি আপনার এমন কোনও ক্লাস থাকে যা প্রাকৃতিকভাবে ঘটে যাওয়া পুনরাবৃত্ত কলের অংশ।

তোমার যদি থাকত:

struct Node
{
    Node* left;
    Node* right;
};

সি তে, আপনি লিখতে পারেন:

void traverse_in_order(Node* n) {
    if(!n) return;
    traverse_in_order(n->left);
    process(n);
    traverse_in_order(n->right);
}

সি ++ তে, এটিকে সদস্য ফাংশন করে তৈরি করা ভাল:

void Node::traverse_in_order() {
    // <--- What check should be put here?
    left->traverse_in_order();
    process();
    right->traverse_in_order();
}

সি ++ (মানীকরণের আগে) এর প্রথম দিনগুলিতে, এটি জোর দেওয়া হয়েছিল যে সদস্য ফাংশনগুলি এমন কোনও ফাংশনের জন্য সিনট্যাকটিক চিনি যেখানে thisপ্যারামিটার অন্তর্ভুক্ত থাকে। কোডটি সি ++ তে লেখা হয়েছিল, সমমানের সি তে রূপান্তরিত হয়েছিল এবং সংকলিত হয়েছিল। এমনকী সুস্পষ্ট thisউদাহরণও ছিল যে শূন্যের সাথে তুলনা করা অর্থবহ ছিল এবং মূল সিফ্রন্ট সংকলকও এর সুবিধা নিয়েছিল। সুতরাং একটি সি পটভূমি থেকে আসা, চেক জন্য সুস্পষ্ট পছন্দ হ'ল:

if(this == nullptr) return;      

দ্রষ্টব্য: বজর্ন স্ট্রস্ট্রপ এমনকি এমনও উল্লেখ করেছেন যে এখানেthis বছরের পর বছর ধরে নিয়মগুলি পরিবর্তিত হয়েছে

এবং এটি বহু বছরের জন্য বহু সংকলকগুলিতে কাজ করে। মানিককরণ যখন ঘটেছিল তখন এটি পরিবর্তিত হয়েছিল। এবং আরও সম্প্রতি, কম্পাইলার সদস্য ফাংশন যেখানে কলিং সুবিধা গ্রহণ শুরু thisহচ্ছে nullptrঅনির্ধারিত আচরণ, যার মানে এই অবস্থা সবসময় হয় false, এবং কম্পাইলার এটা বর্জন করা হয় বিনামূল্যে।

এর অর্থ এই গাছের কোনও আড়াআড়ি করার জন্য আপনার প্রয়োজন হয়:

  • কল করার আগে সমস্ত চেক করুন traverse_in_order

    void Node::traverse_in_order() {
        if(left) left->traverse_in_order();
        process();
        if(right) right->traverse_in_order();
    }

    এর অর্থ হ'ল যদি আপনার নাল রুট থাকতে পারে তবে প্রতিটি কল সাইটে পরীক্ষা করা।

  • সদস্য ফাংশন ব্যবহার করবেন না

    এর অর্থ হ'ল আপনি পুরাতন সি স্টাইল কোডটি (সম্ভবত একটি স্ট্যাটিক পদ্ধতি হিসাবে) লিখছেন এবং অবজেক্টের সাথে এটি স্পষ্টভাবে একটি প্যারামিটার হিসাবে কল করছেন। যেমন। আপনি কল সাইটে Node::traverse_in_order(node);না হয়ে লেখায় ফিরে এসেছেন node->traverse_in_order();

  • আমি বিশ্বাস করি যে এই নির্দিষ্ট উদাহরণটিকে এমনভাবে ঠিক করার সবচেয়ে সহজ / নেটিয়েস্ট উপায় যা মানের সাথে সঙ্গতিপূর্ণ তা হ'ল আসলে একটি এর পরিবর্তে একটি সেন্ডিনেল নোড ব্যবহার করা nullptr

    // static class, or global variable
    Node sentinel;
    
    void Node::traverse_in_order() {
        if(this == &sentinel) return;
        ...
    }

প্রথম দুটি বিকল্পের কোনওটিই আবেদনময়ী বলে মনে হচ্ছে না, এবং কোডটি এটির সাথে সরে যেতে পারে, তবে তারা this == nullptrসঠিক ফিক্স ব্যবহার না করে খারাপ কোড লিখেছিল ।

আমি অনুমান করছি যে এই কয়েকটি কোড ঘাঁটিতে কিভাবে this == nullptrতাদের চেক রয়েছে তা বিকশিত হয়েছিল ।


6
কীভাবে অপরিবর্তিত 1 == 0আচরণ হতে পারে? এটা সহজ false
জোহানেস স্কাউব - লিটব

11
চেক নিজেই একটি সংজ্ঞায়িত আচরণ নয়। এটি কেবল সর্বদা মিথ্যা এবং এভাবে সংকলক দ্বারা মুছে ফেলা হয়।
সের্গেইএ

15
হুম .. this == nullptrমূর্খতা হ'ল অপরিজ্ঞাত আচরণ কারণ আপনি এর আগে নালপ্ট্র অবজেক্টে সদস্য ফাংশনটি বলেছেন, যা অপরিজ্ঞাত। এবং সংকলক চেক বাদ দিতে বিনামূল্যে
jtlim

6
@ জোশুয়া, প্রথম স্ট্যান্ডার্ডটি 1998 সালে প্রকাশিত হয়েছিল। এর আগে যা ঘটেছিল তা প্রতিটি বাস্তবায়ন যা চেয়েছিল তা ছিল। অন্ধকার বয়সের.
সের্গেইএ

26
হেহ, বাহ, আমি বিশ্বাস করতে পারছি না কেউ কি কখনো কোডটি উদাহরণস্বরূপ ফাংশন কলিং ওপরেই নির্ভরশীল লিখেছিলেন ... একটি দৃষ্টান্ত ছাড়া । এমনকি thisঅবিচ্ছিন্ন হওয়ার কথা চিন্তা না করেই আমি সহজাতভাবে "ট্র্যাভার্স_আইন_র্ডার কল করার আগে সমস্ত চেক করুন" চিহ্নযুক্ত উদ্ধৃত অংশটি ব্যবহার করতাম । আমার ধারণা সম্ভবত এমন এক যুগে সি ++ শেখার সুবিধা যা আমার মস্তিস্কে ইউবির বিপদ ডেকে আনার জন্য এসও উপস্থিত রয়েছে এবং আমাকে এই জাতীয় উদ্ভট হ্যাকগুলি থেকে বিরত রাখবে।
আন্ডারস্কোর_

65

এটি ব্যবহার করে কারণ "ব্যবহারিক" কোডটি ভেঙে দেওয়া হয়েছিল এবং এর সাথে শুরু করার জন্য সংজ্ঞায়িত আচরণ জড়িত ছিল। thisএকটি অণু-অপ্টিমাইজেশন হিসাবে সাধারণত নাল ব্যবহার করার কোনও কারণ নেই , সাধারণত খুব অকাল হয়।

এটি একটি বিপজ্জনক অনুশীলন, যেহেতু শ্রেণিবদ্ধ শ্রেণিবিন্যাসের কারণে পয়েন্টারগুলির সামঞ্জস্যটি একটি নালকে একটি নালকে পরিণত thisকরতে পারে। সুতরাং, খুব কমপক্ষে, যে ক্লাসগুলির পদ্ধতিগুলি নাল দিয়ে কাজ করার কথা বলেছে সেগুলি thisঅবশ্যই কোনও বেস ক্লাসের সাথে একটি চূড়ান্ত শ্রেণি হতে হবে: এটি কোনও কিছু থেকে উদ্ভূত হতে পারে না এবং এটি থেকে উত্পন্ন করা যায় না। আমরা দ্রুত ব্যবহারিক থেকে কুৎসিত-হ্যাক-ল্যান্ডের দিকে রওনা হচ্ছি ।

ব্যবহারিক ক্ষেত্রে, কোডটি কুৎসিত হতে হবে না:

struct Node
{
  Node* left;
  Node* right;
  void process();
  void traverse_in_order() {
    traverse_in_order_impl(this);
  }
private:
  static void traverse_in_order_impl(Node * n)
    if (!n) return;
    traverse_in_order_impl(n->left);
    n->process();
    traverse_in_order_impl(n->right);
  }
};

যদি আপনার একটি খালি গাছ থাকে (উদা। রুট নাল্পটার), এই দ্রবণটি এখনও নাল্প্টারের সাথে ট্র্যাভার্স_ইন_র্ডার কল করে অপরিজ্ঞাত আচরণের উপর নির্ভর করছে।

যদি গাছটি খালি থাকে, ওরফে একটি নাল Node* root, আপনি এটির উপর কোনও স্থিতিশীল পদ্ধতি কল করার কথা নেই। সময়কাল। সি-জাতীয় ট্রি কোড থাকা পুরোপুরি ঠিক আছে যা একটি সুস্পষ্ট পরামিতি দ্বারা একটি উদাহরণ পয়েন্টার নেয়।

এখানে যুক্তিটি একরকম উত্থিত হয়েছে বলে মনে হচ্ছে যে কোনও বস্তুগুলিকে নাল উদাহরণ পয়েন্টার থেকে ডেকে আনা যেতে পারে এমন স্থিতিশীল পদ্ধতিগুলি লিখতে হবে। এরকম কোনও দরকার নেই। এই জাতীয় কোড লেখার সি-সহ-অবজেক্টগুলি সি ++ বিশ্বে এখনও বেশ সুন্দর, কারণ এটি খুব কমপক্ষে সুরক্ষিত হতে পারে। মূলত, নালটি thisএমন সংক্ষিপ্ত ক্ষেত্রের সাথে মাইক্রো-অপ্টিমাইজেশন, এটি অস্বীকার করা আইএমএইচও পুরোপুরি ঠিক আছে। কোনও পাবলিক এপিআই কোনও নালার উপর নির্ভর করবে না this


18
@ বেন, যে কেউ এই কোডটি লিখেছিল সে প্রথম স্থানে ভুল ছিল। মজার বিষয় যে আপনি এমএফসি, কিউটি এবং ক্রোমিয়াম হিসাবে এই জাতীয় ভয়ঙ্কর ভাঙা প্রকল্পগুলির নাম দিচ্ছেন। তাদের সাথে ভাল riddance।
সের্গেইএ

19
@ বেন, গুগলের ভয়ানক কোডিং শৈলীগুলি আমার কাছে সুপরিচিত। গুগল কোড (কমপক্ষে প্রকাশ্যে উপলভ্য) প্রায়শই খারাপভাবে লেখা হয়, একাধিক লোক গুগল কোডকে উজ্জ্বল উদাহরণ হিসাবে বিশ্বাস করেও despite হতে পারে এটি তাদের কোডিং শৈলীর পুনর্বিবেচনা করতে সক্ষম করবে (এবং তারা যখন এটিতে থাকবে তখন গাইডলাইন)।
সের্গেইএ

18
@ বেন এই ডিভাইসে কোনও ক্রোমিয়ামকে জিসিসি using ব্যবহার করে সংকলিত ক্রোমিয়ামকে প্রত্যাবর্তনমূলকভাবে পুনঃস্থাপন করছে না Chr এটিও বিশাল কাজ নয়; thisবিভিন্ন স্ট্যাটিক কোড বিশ্লেষকরা এই চেকগুলি বেছে নিয়েছেন, সুতরাং এটির মতো নয় যে কাউকে নিজেই সেগুলি সমস্ত অনুসন্ধান করতে হবে। প্যাচটি হতে পারে তুচ্ছ পরিবর্তনের কয়েক শতাধিক লাইন।
মনিকা 15

8
@ বেন ব্যবহারিক ভাষায়, একটি নাল thisডিফারেন্স তাত্ক্ষণিক ক্রাশ। এই কোডগুলি কোডের উপর দিয়ে কোনও স্ট্যাটিক বিশ্লেষক চালানোর বিষয়ে চিন্তা না করে এমনকি খুব দ্রুত এই সমস্যাগুলি খুঁজে পাওয়া যাবে। সি / সি ++ মন্ত্রটি "কেবলমাত্র আপনার ব্যবহৃত বৈশিষ্ট্যের জন্য অর্থ প্রদান করুন" মন্ত্রটি অনুসরণ করে। আপনি যদি চেকগুলি চান, আপনার অবশ্যই তাদের সম্পর্কে স্পষ্ট হওয়া উচিত এবং এর অর্থ thisএটি খুব বেশি দেরী হওয়ার পরে এগুলি না করা , যেহেতু সংকলকটি অনুমান করে যে thisএটি বাতিল নয়। অন্যথায় এটি পরীক্ষা করে দেখতে হবে thisএবং 99.9999% কোডের জন্য এই জাতীয় চেকগুলি সময় নষ্ট হয়।
মনিকা 15

10
যে কেউ ভাবেন যে স্ট্যান্ডার্ডটি নষ্ট হয়েছে: তার জন্য আলাদা আলাদা ভাষা ব্যবহার করুন। সি ++ এর অভাব নেই - এমন ভাষাগুলির মতো যা অনির্ধারিত আচরণের সম্ভাবনা রাখে না।
এমএম

35

পরিবর্তন দস্তাবেজটি স্পষ্টতই এটি বিপজ্জনক হিসাবে আখ্যায়িত করে কারণ এটি প্রায়শই ব্যবহৃত কোডের একটি বিস্ময়কর পরিমাণ ভঙ্গ করে।

নথিটি এটিকে বিপজ্জনক বলে অভিহিত করে না। বা এটি দাবি করে না যে এটি একটি আশ্চর্যজনক কোডটি ভঙ্গ করে । এটি কেবল কয়েকটি জনপ্রিয় কোড বেসগুলি নির্দেশ করে যা দাবি করে যে এটি এই অপরিজ্ঞাত আচরণের উপর নির্ভর করে এবং পরিবর্তনের কারণে ভেঙে যাবে যদি না কর্মক্ষম বিকল্পটি ব্যবহার করা হয়।

এই নতুন অনুমানটি ব্যবহারিক সি ++ কোডটি কেন ভেঙে দেবে?

যদি ব্যবহারিক সি ++ কোড অপরিজ্ঞাত আচরণের উপর নির্ভর করে, তবে সেই অপরিজ্ঞাত আচরণে পরিবর্তনগুলি এটি ভেঙে দিতে পারে। এজন্য ইউবি এড়ানো উচিত, এমনকি যখন কোনও প্রোগ্রামের উপর নির্ভর করে তখনও উদ্দেশ্য হিসাবে কাজ করে।

এমন কোনও নিদর্শন রয়েছে যেখানে অযত্ন বা অজানা প্রোগ্রামাররা এই নির্দিষ্ট অপরিজ্ঞাত আচরণের উপর নির্ভর করে?

আমি জানি না এটি বিস্তৃতভাবে অ্যান্টি- প্যাটার্ন ছড়িয়ে রয়েছে কিনা, তবে একটি অজ্ঞাত প্রোগ্রামার মনে করতে পারে যে তারা তাদের প্রোগ্রামটি ক্রাশ হওয়া থেকে ঠিক করে দিতে পারে:

if (this)
    member_variable = 42;

যখন আসল বাগটি অন্য কোথাও একটি নাল পয়েন্টারকে ডিফারেন্স করছে।

আমি নিশ্চিত যে যদি প্রোগ্রামার পর্যাপ্ত পরিমাণে অবহিত হয় তবে তারা এই ইউবির উপর নির্ভরশীল আরও উন্নত (অ্যান্টি) প্যাটার্ন নিয়ে আসতে সক্ষম হবে।

আমি কারও লেখার কল্পনাও করতে পারি না if (this == NULL)কারণ এটি এতটাই অপ্রাকৃত।

আমি পারি.


11
"যদি ব্যবহারিক সি ++ কোড অপরিজ্ঞাত আচরণের উপর নির্ভর করে, তবে সেই অপরিজ্ঞাত আচরণে পরিবর্তনগুলি এটি ভেঙে ফেলতে পারে This এজন্য ইউবিকে এড়াতে হবে" এই * 1000
আন্ডারস্কোর_আর

if(this == null) PrintSomeHelpfulDebugInformationAboutHowWeGotHere(); যেমন ইভেন্টগুলির ক্রমের একটি সহজেই সহজে পঠনযোগ্য পড়ার লগ যা কোনও ডিবাগার আপনাকে সহজেই বলতে পারে না। আপনি লিখে নেই এমন কোডে কোনও বড় ডেটা সেটটিতে হঠাৎ এলোমেলো শূন্যতা উপস্থিত থাকার সময় ঘন ঘন পরীক্ষা করে না রেখে এখনই এটি ডিবাগ করতে মজা করুন ... এবং সি ++ তৈরি হওয়ার পরে ইউবি নিয়মটি পরে তৈরি করা হয়েছিল। এটি বৈধ ছিল।
স্টিফেন হকেনহুল

@StephaneHockenhull যে কি -fsanitize=nullজন্য হয়।
এরেরিকা

@ ব্যবহারকারী 2079303 ইস্যুগুলি: এটি কি প্রোডাকশন কোডকে এমন ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে নিয়ে যাচ্ছে যেখানে আপনি চলমান অবস্থায় চেক ইন ছাড়তে পারবেন না, সংস্থাকে প্রচুর অর্থ ব্যয় করতে হবে? এটি কি আকার বাড়াতে চলেছে এবং ফ্ল্যাশের সাথে মানাবে না? এটি কি আতেল সহ সমস্ত লক্ষ্য প্ল্যাটফর্মগুলিতে কাজ করে? -fsanitize=nullপিন # 5,6,10,11 এসপিআই ব্যবহার করে এসডি / এমএমসি কার্ডে ত্রুটিগুলি লগ করতে পারেন ? এটি কোনও সার্বজনীন সমাধান নয়। কেউ কেউ যুক্তি দেখিয়েছেন যে কোনও নাল বস্তু অ্যাক্সেস করা অবজেক্ট-ওরিয়েন্টেড নীতিগুলির বিরুদ্ধে যায় তবে কিছু ওওপি ভাষার একটি নাল বস্তু রয়েছে যা এটি পরিচালনা করতে পারে তাই এটি ওওপির সর্বজনীন নিয়ম নয়। 1/2
স্টিফেন হকেনহুল

1
... একটি নিয়মিত প্রকাশ যা এই ধরনের ফাইলের সাথে মেলে? এই বলে যে উদাহরণস্বরূপ যদি কোনও ল্যাভেলু দু'বার অ্যাক্সেস করা হয় তবে একটি সংকলক সংস্থাগুলি অ্যাক্সেসগুলিকে একত্রীকরণ করতে পারে যদি না তাদের মধ্যে কোড নির্দিষ্ট কোডগুলির মধ্যে কিছু না করে যেখানে স্টোরেজ অ্যাক্সেসের অনুমতি দেওয়া হয়েছে সেই নির্দিষ্ট অবস্থার সংজ্ঞা দেওয়ার চেষ্টা করার চেয়ে অনেক সহজ হবে be
সুপারক্যাট

25

কিছু "ব্যবহারিক" ("বগি" বানান করার মজার উপায়) কোডটি ভেঙে দেওয়া দেখে মনে হয়েছিল:

void foo(X* p) {
  p->bar()->baz();
}

এবং এটি p->bar()কখনও কখনও নাল পয়েন্টারটি ফেরত দেয় এর জন্য অ্যাকাউন্ট করতে ভুলে যায় , যার অর্থ এটি কল করার baz()জন্য এটিকে অবমূল্যায়ন করা হয় না।

সমস্ত কোড যা ভেঙেছিল তাতে স্পষ্ট if (this == nullptr)বা if (!p) return;চেক থাকে না contained কিছু ক্ষেত্রে কেবল এমন ফাংশন ছিল যা কোনও সদস্যের ভেরিয়েবল অ্যাক্সেস করতে পারে না এবং তাই ঠিক আছে কাজ করার জন্য হাজির । উদাহরণ স্বরূপ:

struct DummyImpl {
  bool valid() const { return false; }
  int m_data;
};
struct RealImpl {
  bool valid() const { return m_valid; }
  bool m_valid;
  int m_data;
};

template<typename T>
void do_something_else(T* p) {
  if (p) {
    use(p->m_data);
  }
}

template<typename T>
void func(T* p) {
  if (p->valid())
    do_something(p);
  else 
    do_something_else(p);
}

এই কোডে আপনি যখন func<DummyImpl*>(DummyImpl*)নাল পয়েন্টার দিয়ে কল করেন তখন কল করার জন্য পয়েন্টারটির একটি "ধারণাগত" অবজ্ঞা থাকে p->DummyImpl::valid(), কিন্তু বাস্তবে সদস্য ফাংশনটি falseঅ্যাক্সেস ছাড়াই ফিরে আসে *this। এটি return falseইনলাইন করা যেতে পারে এবং তাই অনুশীলনে পয়েন্টারটি একেবারেই অ্যাক্সেস করার প্রয়োজন হয় না। সুতরাং কিছু সংকলকগুলির সাথে এটি ঠিক আছে বলে মনে হচ্ছে: নালকে মূল্যহীন করার জন্য কোনও সেগফল্ট নেই, p->valid()এটি মিথ্যা, তাই কোড কল করে do_something_else(p)যা নাল পয়েন্টারগুলির জন্য পরীক্ষা করে, এবং তেমন কিছুই করে না। কোনও ক্রাশ বা অপ্রত্যাশিত আচরণ পরিলক্ষিত হয় না।

জিসিসি 6 এর সাথে আপনি এখনও কল পেয়েছেন p->valid()তবে সংকলকটি এখন সেই অভিব্যক্তিটি থেকে অনুমান করে যা pঅবশ্যই নন-নাল p->valid()হতে হবে (অন্যথায় অপরিজ্ঞাত আচরণ হবে) এবং সেই তথ্যের একটি নোট তৈরি করে। যে অনুমিত তথ্য অপটিমাইজার দ্বারা ব্যবহৃত হয়, যাতে কলে যদি do_something_else(p)inlined পরার, if (p)চেক এখন অপ্রয়োজনীয় বলে মনে করা হয়, কারণ কম্পাইলার স্মরণ এটি নাল নয়, এবং তাই কোড inlines:

template<typename T>
void func(T* p) {
  if (p->valid())
    do_something(p);
  else {
    // inlined body of do_something_else(p) with value propagation
    // optimization performed to remove null check.
    use(p->m_data);
  }
}

এটি এখন সত্যই একটি নাল পয়েন্টারকে অবজ্ঞা করে এবং তাই কোড যা পূর্বে কাজ করেছিল তা কাজ করা বন্ধ করে দেয়।

এই উদাহরণে বাগটি রয়েছে func, যা প্রথমে শূন্যের জন্য পরীক্ষা করা উচিত ছিল (বা কলকারীরা এটিকে কখনই নাল দিয়ে ডাকেনি):

template<typename T>
void func(T* p) {
  if (p && p->valid())
    do_something(p);
  else 
    do_something_else(p);
}

একটি গুরুত্বপূর্ণ বিষয় মনে রাখবেন যে এর মতো বেশিরভাগ অপ্টিমাইজেশানগুলি সংকলক বলে না যে "আহ, প্রোগ্রামার এই পয়েন্টারটিকে শূন্যের বিরুদ্ধে পরীক্ষা করেছে, আমি এটি কেবল বিরক্ত করার জন্য সরিয়ে ফেলব"। যা ঘটে তা হ'ল মিলের বিভিন্ন অপটিমাইজেশনের মতো ইনলাইনিং এবং মান পরিসীমা প্রচারগুলি এই চেকগুলিকে অতিরিক্ত কাজ করার জন্য একত্রিত করে, কারণ তারা আগের পরীক্ষার পরে বা একটি নির্ধারণের পরে আসে। যদি সংকলকটি জানে যে কোনও ফাংশনে A বিন্দুতে কোনও পয়েন্টার অ-শূন্য হয় এবং একই ফাংশনটির পরে বিন্দু B এর আগে পয়েন্টারটি পরিবর্তন হয় না, তবে এটি জানে যে এটি বি-তেও নাল নয় When পয়েন্ট এ এবং বি প্রকৃতপক্ষে কোডের টুকরা হতে পারে যা মূলত পৃথক ফাংশনে ছিল তবে এখন কোডের এক টুকরোতে একত্রিত হয় এবং সংকলকটি তার জ্ঞানটি প্রয়োগ করতে সক্ষম হয় যে পয়েন্টারটি আরও জায়গায় নন-নাল।


যখন এই জাতীয় ব্যবহারের মুখোমুখি হয় তখন কি সংকলন-সময় সতর্কতাগুলি আউটপুট দেওয়ার জন্য জিসিসি 6 চালানো সম্ভব this?
jotik


3
@ জোটিক, C টিসি কী বলেছে। এটি সম্ভব হবে, তবে আপনি সমস্ত কোড, সমস্ত সময়ের জন্য সেই সতর্কতাটি পেয়ে যাবেন । মান পরিসীমা প্রচার সবচেয়ে সাধারণ অপ্টিমাইজেশানগুলির মধ্যে একটি, যা প্রায় সমস্ত কোডকেই প্রভাবিত করে, সর্বত্র। অপ্টিমাইজারগুলি কেবল কোড দেখতে পাবে, যা সরলতর করা যেতে পারে। তারা দেখতে পাবে না "একটি নির্বোধের দ্বারা লেখা কোডের টুকরো যা তাদের বোবা ইউবিটি অপ্টিমাইজড হয়ে গেলে সতর্ক করতে চায়"। "প্রোগ্রামারটি অপ্টিমাইজড হতে চায়" এবং "প্রোগ্রামার মনে করে যে রিডানড্যান্ট চেক যা প্রোগ্রামার মনে করে সাহায্য করবে, তবে এটি অপ্রয়োজনীয়" এর মধ্যে পার্থক্যটি সংকলকের পক্ষে বলা সহজ নয়।
জোনাথন ওয়েকেলি

1
যদি আপনি আপনার কোডটি বিভিন্ন ধরণের ইউবি-র জন্য রানটাইম ত্রুটিগুলি দিতে অবৈধ ব্যবহারগুলি thisব্যবহার করতে চান তবে কেবল ব্যবহার করুন-fsanitize=undefined
জোনাথন ওয়েকেলি


-25

সি ++ স্ট্যান্ডার্ডটি গুরুত্বপূর্ণ উপায়ে নষ্ট হয়ে গেছে। দুর্ভাগ্যক্রমে, ব্যবহারকারীদের এই সমস্যাগুলি থেকে রক্ষা করার পরিবর্তে, জিসিসি বিকাশকারীরা প্রান্তিক আশাবাদী প্রয়োগের অজুহাত হিসাবে অপরিজ্ঞাত আচরণকে বেছে নিয়েছে, এমনকি এটি তাদের পক্ষে কীভাবে ক্ষতিকারক তা পরিষ্কার করে ব্যাখ্যা করা হয়েছে।

এখানে আমার চেয়ে অনেক চালাক ব্যক্তি খুব বিস্তারিতভাবে ব্যাখ্যা করেছেন। (সে সি সম্পর্কে কথা বলছে তবে সেখানে পরিস্থিতি একই রকম)।

কেন এটি ক্ষতিকারক?

সহজভাবে পূর্বে কাজ করা, সংকলকটির নতুন সংস্করণ সহ সুরক্ষিত কোডগুলি সুরক্ষা দুর্বলতার পরিচয় দিতে পারে । যদিও নতুন আচরণটি একটি পতাকা দিয়ে অক্ষম করা যেতে পারে, বিদ্যমান মেকফিলগুলিতে অবশ্যই পতাকা পতাকা সেট নেই। এবং যেহেতু কোনও সতর্কতা তৈরি করা হয় নি, বিকাশকারীদের কাছে এটি স্পষ্ট নয় যে পূর্বের যুক্তিসঙ্গত আচরণটি পরিবর্তিত হয়েছে।

এই উদাহরণে, বিকাশকারী ব্যবহার করে পূর্ণসংখ্যার ওভারফ্লোর জন্য একটি চেক অন্তর্ভুক্ত করেছে assert, যা কোনও অবৈধ দৈর্ঘ্য সরবরাহ করা হলে প্রোগ্রামটি শেষ করে দেবে। জিসিসি টিম এই ভিত্তিতে চেকটি সরিয়ে ফেলল যে পূর্ণসংখ্যার ওভারফ্লো অপরিজ্ঞাত, তাই চেকটি সরানো যেতে পারে। এর ফলস্বরূপ সমস্যাটি স্থির হয়ে যাওয়ার পরে এই কোডবেজটিকে পুনরায় দুর্বল করে তোলার প্রকৃত অনন্য দৃষ্টান্ত তৈরি হয়েছিল।

পুরো জিনিস পড়ুন। আপনাকে কেঁদে ফেলার জন্য এটি যথেষ্ট।

ঠিক আছে, তবে এই সম্পর্কে কি?

যখন ফিরে আসি তখন মোটামুটি প্রচলিত প্রথা ছিল যা এরকম কিছু হয়েছিল:

 OPAQUEHANDLE ObjectType::GetHandle(){
    if(this==NULL)return DEFAULTHANDLE;
    return mHandle;

 }

 void DoThing(ObjectType* pObj){
     osfunction(pObj->GetHandle(), "BLAH");
 }

আইডিয়ামটি হ'ল: যদি pObjশূন্য না হয় তবে আপনি এতে থাকা হ্যান্ডেলটি ব্যবহার করেন, অন্যথায় আপনি একটি ডিফল্ট হ্যান্ডেল ব্যবহার করেন। এটি GetHandleফাংশনে এনক্যাপসুলেটেড হয় ।

কৌশলটি হ'ল অ-ভার্চুয়াল ফাংশনটি কল করা আসলে thisপয়েন্টারটির কোনও ব্যবহার করে না , তাই অ্যাক্সেস লঙ্ঘন নেই।

আমি এখনও এটি পাই না

প্রচুর কোড বিদ্যমান যা এটির মতো লেখা। যদি কেউ লাইন পরিবর্তন না করে কেবল এটিকে পুনরায় DoThing(NULL)সংশোধন করে তবে প্রতিটি কলই ক্র্যাশ করা বাগ is যদি আপনি ভাগ্যবান হন।

আপনি ভাগ্যবান না হলে, ক্র্যাশিং বাগগুলিতে কলগুলি দূরবর্তী প্রয়োগের দুর্বলতায় পরিণত হয়।

এটি এমনকি স্বয়ংক্রিয়ভাবে ঘটতে পারে। আপনি একটি স্বয়ংক্রিয় বিল্ড সিস্টেম পেয়েছেন, তাই না? সর্বশেষতম সংকলকটিতে এটি আপগ্রেড করা ক্ষতিকারক, তাই না? তবে এখন তা নয় - আপনার সংকলকটি যদি জিসিসি হয় তবে তা নয়।

ঠিক আছে তাই তাদের বলুন!

তাদের বলা হয়েছে। পরিণতিগুলির সম্পূর্ণ জ্ঞানে তারা এটি করছে।

কিন্তু কেন?

কে বলতে পারে? সম্ভবত:

  • তারা প্রকৃত কোডের তুলনায় সি ++ ভাষার আদর্শ বিশুদ্ধতার মূল্য দেয়
  • তারা বিশ্বাস করে যে মান অনুসরণ না করার জন্য লোকদের শাস্তি দেওয়া উচিত
  • পৃথিবীর বাস্তবতা সম্পর্কে তাদের কোন ধারণা নেই
  • তারা ... উদ্দেশ্য অনুযায়ী বাগ প্রবর্তন করা হয়। সম্ভবত কোনও বিদেশী সরকারের পক্ষে। আপনি কোথায় বাস করেন? সমস্ত সরকারই বিশ্বের বেশিরভাগ দেশের কাছে বিদেশী এবং বেশিরভাগ বিশ্বের কিছু দেশ বিরোধী।

বা সম্ভবত অন্য কিছু। কে বলতে পারে?


32
উত্তরের প্রতিটি এবং একক লাইনের সাথে দ্বিমত পোষণ করুন। কঠোর aliasing অনুকূলকরণের জন্য একই মন্তব্য করা হয়েছিল, এবং যারা আশাবাদী এখন তা বরখাস্ত করা হয়। সমাধানটি হ'ল বিকাশকারীদের শিক্ষিত করা, খারাপ বিকাশের অভ্যাসের ভিত্তিতে অপ্টিমাইজেশন প্রতিরোধ করা নয়।
সের্গেইএ

30
আপনি গিয়েছিলেন বলে পুরোটা পড়ে গিয়েছিলাম এবং সত্যিই আমি কেঁদেছিলাম, তবে মূলত ফেলিক্সের বোকামির দিকে যা আমি মনে করি না যে আপনি যা করার চেষ্টা করছিলেন ...
মাইক ভাইন

33
অকেজো ভাড়ার জন্য ডাউনভোটেড। "তারা ... উদ্দেশ্যমূলকভাবে বাগ প্রবর্তন করছে Perhaps সম্ভবত কোনও বিদেশী সরকারের জন্য।" সত্যি? এটি / আর / ষড়যন্ত্র নয়।
ইসানায়ে

31
মার্জিত প্রোগ্রামগুলি বারবার পুনরাবৃত্তি করে মন্ত্রটি অনির্ধারিত আচরণের জন্য ডাকে না , তবুও এই ননকগুলি এগিয়ে গেছে এবং যাইহোক এটি করেছে। এবং দেখুন কি ঘটেছে। আমার যা কিছু আছে তা নিয়ে কোনও সহানুভূতি নেই। এটি বিকাশকারীদের দোষ, এটি সাধারণ। তাদের দায়িত্ব নেওয়া দরকার। মনে রাখবেন, যে? ব্যক্তিগত দায়িত্ব? জনসাধারণ "সম্পর্কে কিন্তু কি আপনার মন্ত্রোচ্চারণের উপর নির্ভর বাস্তবে !" এই পরিস্থিতিটি প্রথম স্থানে কীভাবে উত্থিত হয়েছিল তা অবিকল। এর মতো বাজে কথা এড়ানো এটাই হ'ল মান কেন প্রথম স্থানে থাকে। মানগুলিতে কোড করুন এবং আপনার কোনও সমস্যা হবে না। সময়কাল।
অরবিট

18
"সহজভাবে পূর্বে কাজ করা, সংকলকটির নতুন সংস্করণ সহ সুরক্ষিত কোডগুলি সুরক্ষা দুর্বলতার পরিচয় দিতে পারে" - যা সর্বদা ঘটে । আপনি যদি আদেশ দিতে না চান তবে একটি সংকলকের এক সংস্করণ হ'ল একমাত্র সংকলক যা বাকী চিরন্তন মঞ্জুরিপ্রাপ্ত। আপনার কি মনে আছে যখন লিনাক্স কার্নেলটি কেবলমাত্র gcc 2.7.2.1 দিয়ে সংকলিত হতে পারে? জিসিসি প্রকল্পটি এমনকি কাঁটাযুক্ত হয়ে গেছে কারণ লোকেরা বুলক্র্যাপ দিয়ে বিরক্ত হয়েছিল। এর অতীত হতে দীর্ঘ সময় লেগেছিল।
এমএম
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.