জিসিসির সাথে x86 এ পূর্ণসংখ্যা ওভারফ্লো কেন অসীম লুপের কারণ?


129

নিম্নলিখিত কোডটি জিসিসিতে একটি অসীম লুপে যায়:

#include <iostream>
using namespace std;

int main(){
    int i = 0x10000000;

    int c = 0;
    do{
        c++;
        i += i;
        cout << i << endl;
    }while (i > 0);

    cout << c << endl;
    return 0;
}

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

অতএব, আমি এটি অপরিশোধিত আচরণ সত্ত্বেও - এটি ওভারফ্লোতে আবৃত হওয়ার প্রত্যাশা করতাম। তবে এটি স্পষ্টভাবে কেস নয়। তাহলে আমি কী মিস করলাম?

আমি এটি ব্যবহার করে সংকলন করেছি:

~/Desktop$ g++ main.cpp -O2

জিসিসি আউটপুট:

~/Desktop$ ./a.out
536870912
1073741824
-2147483648
0
0
0

... (infinite loop)

অপ্টিমাইজেশান অক্ষম থাকায় কোনও অসীম লুপ নেই এবং আউটপুট সঠিক। ভিজ্যুয়াল স্টুডিওও এটি সঠিকভাবে সংকলন করে এবং নিম্নলিখিত ফলাফল দেয়:

সঠিক আউটপুট:

~/Desktop$ g++ main.cpp
~/Desktop$ ./a.out
536870912
1073741824
-2147483648
3

এখানে আরও কিছু ভিন্নতা রয়েছে:

i *= 2;   //  Also fails and goes into infinite loop.
i <<= 1;  //  This seems okay. It does not enter infinite loop.

এখানে সম্পর্কিত সমস্ত সংস্করণ তথ্য রয়েছে:

~/Desktop$ g++ -v
Using built-in specs.
COLLECT_GCC=g++
COLLECT_LTO_WRAPPER=/usr/lib/x86_64-linux-gnu/gcc/x86_64-linux-gnu/4.5.2/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ..

...

Thread model: posix
gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4) 
~/Desktop$ 

সুতরাং প্রশ্নটি হ'ল: এটি কি জিসিসিতে একটি বাগ? বা জিসিসি কীভাবে পূর্ণসংখ্যার গাণিতিক পরিচালনা করে সে সম্পর্কে আমি কিছু ভুল বুঝেছি?

* আমি এই সিটিকেও ট্যাগ করছি, কারণ আমি ধরে নিয়েছি যে এই বাগটি সি-এ পুনরুত্পাদন করবে (আমি এখনও এটি যাচাই করি নি))

সম্পাদনা করুন:

লুপের সমাবেশটি এখানে:

.L5:
addl    %ebp, %ebp
movl    $_ZSt4cout, %edi
movl    %ebp, %esi
.cfi_offset 3, -40
call    _ZNSolsEi
movq    %rax, %rbx
movq    (%rax), %rax
movq    -24(%rax), %rax
movq    240(%rbx,%rax), %r13
testq   %r13, %r13
je  .L10
cmpb    $0, 56(%r13)
je  .L3
movzbl  67(%r13), %eax
.L4:
movsbl  %al, %esi
movq    %rbx, %rdi
addl    $1, %r12d
call    _ZNSo3putEc
movq    %rax, %rdi
call    _ZNSo5flushEv
cmpl    $3, %r12d
jne .L5

10
আপনি যদি উত্পন্ন সমাবেশ কোডটি অন্তর্ভুক্ত করেন তবে এটি আরও অনেক জবাবদিহি হবে gcc -S
গ্রেগ হিউগিল

সমাবেশটি আশ্চর্যজনকভাবে দীর্ঘ। আমি এখনও এটি সম্পাদনা করা উচিত?
রহস্যময়

দয়া করে আপনার লুপের সাথে সম্পর্কিত অংশগুলি।
গ্রেগ হিউগিল

12
-1। আপনি বলছেন যে এটি অনির্ধারিত আচরণটি কঠোরভাবে বলছে এবং জিজ্ঞাসা করুন এটি কি অনির্ধারিত আচরণ। সুতরাং এটি আমার কাছে আসল প্রশ্ন নয়।
জোহানেস স্কাউব -

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

উত্তর:


178

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

হ্যাঁ, x86 সিপিইউতে, পূর্ণসংখ্যাগুলি সাধারণত আপনি যেভাবে প্রত্যাশা করেন তা মোড়ানো হয়। এটি সেই ব্যতিক্রমগুলির মধ্যে একটি। সংকলকটি ধরে নিয়েছে যে আপনি অপরিজ্ঞাত আচরণের কারণ করবেন না এবং লুপ পরীক্ষাটি অপছন্দ করে। আপনি যদি সত্যিই মোড়ক চান, সংকলন -fwrapvকরতে g++বা gccযখন পাস ; এটি আপনাকে সু-সংজ্ঞায়িত (দ্বিগুণ-পরিপূরক) ওভারফ্লো শব্দার্থক দেয়, তবে কার্যকারিতা ক্ষতি করতে পারে।


24
কি শান্তি. আমি সচেতন ছিলাম না -fwrapv। এই বিষয়টি চিহ্নিত করার জন্য ধন্যবাদ.
রহস্যময়

1
এমন কোনও সতর্কতা বিকল্প রয়েছে যা দুর্ঘটনাজনিত অসীম লুপগুলি লক্ষ্য করার চেষ্টা করে?
জেফ বার্ডেজ

5
: আমি -Wunsafe-লুপ-অপ্টিমাইজেশন এখানে উল্লেখ পাওয়া stackoverflow.com/questions/2982507/...
জেফ Burdges

1
-1 "হ্যাঁ, x86 সিপিইউতে, পূর্ণসংখ্যাগুলি সাধারণত আপনি যেভাবে প্রত্যাশা করেন তা মোড়ানো হয়" " ওইটা ভুল. তবে এটি সূক্ষ্ম যেমন আমি মনে করি তাদেরকে ওভারফ্লোতে আটকা পড়া সম্ভব, তবে আমরা এখানে যা বলছি তা তা নয় এবং আমি কখনই এটি সম্পন্ন করে দেখিনি। এটি ব্যতীত এবং x86 বিসিডি অপারেশনগুলিকে উপেক্ষা করা (সি ++ তে উপস্থাপনের অনুমতি নেই) x86 পূর্ণসংখ্যার অপ্সটি সর্বদা মোড়ানো থাকে কারণ তারা দু'জনের পরিপূরক। আপনি x 86 পূর্ণসংখ্যা অপের সম্পত্তি হিসাবে জি ++ ত্রুটিযুক্ত (বা অত্যন্ত অবৈধ এবং বাজে কথা) অপ্টিমাইজেশনটি ভুল করছেন।
চিয়ার্স এবং এইচটিএইচ - আল্ফ

5
@ চিয়ারসান্থ.-আল্ফ, 'x86 সিপিইউ'র দ্বারা' আমি বলতে চাইছি 'আপনি যখন সি কম্পাইলার ব্যবহার করে x86 সিপিইউ'র জন্য বিকাশ করছেন'। আমার কি সত্যিই এটির বানান দরকার? স্পষ্টতই সংকলক এবং জিসিসি সম্পর্কে আমার সমস্ত কথা অপ্রাসঙ্গিক যদি আপনি এসেম্বলারের বিকাশ করে থাকেন, সেক্ষেত্রে পূর্ণসংখ্যার উপরি প্রবাহের জন্য শব্দার্থবিজ্ঞানটি সত্যই খুব ভালভাবে সংজ্ঞায়িত হয়েছে।
বিডোনল

18

এটি সহজ: অপরিবর্তিত আচরণ - বিশেষত অপ্টিমাইজেশান ( -O2) চালু থাকা - এর অর্থ যা কিছু ঘটতে পারে।

আপনার কোডটি -O2স্যুইচ ছাড়াই (আপনি) প্রত্যাশিত আচরণ করে ।

এটি আইসিএল এবং টিসিসি দিয়ে বেশ সূক্ষ্মভাবে কাজ করে তবে আপনি এ জাতীয় স্টাফের উপর নির্ভর করতে পারবেন না ...

মতে এই , জিসিসি অপ্টিমাইজেশান প্রকৃতপক্ষে ওভারফ্লো পূর্ণসংখ্যা স্বাক্ষরিত কীর্তিকলাপ। এর অর্থ হ'ল "বাগ" নকশা দ্বারা।


এটি বিন্দু সাফল্য যে সংকলক অপরিজ্ঞাত আচরণের জন্য সমস্ত জিনিসের অসীম লুপটি বেছে নেবে।
উল্টো

27
@ বিপরীত: আমি একমত নই আপনি যদি সংজ্ঞায়িত আচরণ দিয়ে কিছু কোড করে থাকেন তবে অসীম লুপের জন্য প্রার্থনা করুন। এটি সনাক্ত করা সহজ করে তোলে ...
ডেনিস

আমি বোঝাতে চাইছি যে সংকলক সক্রিয়ভাবে ইউবির সন্ধান করছে, ভাঙা কোডটিকে হাইপার-অপ্টিমাইজ করার চেষ্টা করার পরিবর্তে কেন একটি ব্যতিক্রম সন্নিবেশ করবে না?
ইনভার্স

15
@ বিপরীত: সংকলক সক্রিয়ভাবে অনির্ধারিত আচরণের সন্ধান করছে না , এটি ধরে নেয় যে এটি ঘটেনি। এটি সংকলক কোডটি অনুকূলিতকরণ করতে দেয়। উদাহরণস্বরূপ, কম্পিউটিংয়ের পরিবর্তে for (j = i; j < i + 10; ++j) ++k;এটি কেবলমাত্র সেট হয়ে যাবে k = 10, কারণ কোনও স্বাক্ষরিত ওভারফ্লো না ঘটলে এটি সর্বদা সত্য হবে ।
ডেনিস

@ বিপরীত সংকলক কোনও কিছুর জন্য "অপ্ট" করেনি। আপনি আপনার কোডে লুপ লিখেছেন। সংকলক এটি আবিষ্কার করেনি।
অরবিটে 4-10 ই

13

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

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



3

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


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

7
ভুল। কি হবে যে জিসিসি অনুমান করা আপনি অনির্ধারিত আচরণ ডাকা, তাই এটি শুধু কোড নির্গত করা হবে না দেয়া হয় যেন এটা ঘটতে পারল না। এটা যদি না ঘটে, নির্দেশাবলী তোমার সাথে কি জন্য অনুরোধ করতে কোন অনির্ধারিত আচরণ মৃত্যুদন্ড কার্যকর পেতে, এবং ফলাফল যাই হোক না কেন CPU- র নেই। অর্থাৎ, x86 এ x86 স্টাফ রয়েছে। যদি এটি অন্য প্রসেসর হয় তবে এটি সম্পূর্ণ আলাদা কিছু করতে পারে। বা সংকলকটি আপনি যে অপরিজ্ঞাত আচরণের জন্য আহ্বান করছেন এবং নেটচ্যাক শুরু করছেন তা বোঝার জন্য যথেষ্ট স্মার্ট হতে পারে (হ্যাঁ, জিসিসির কয়েকটি প্রাচীন সংস্করণ ঠিক এটি করেছিল)।
ভোনব্র্যান্ড

4
আমি বিশ্বাস করি আপনি আমার মন্তব্য ভুল লিখেছেন। আমি বলেছিলাম: "আমি যা প্রত্যাশা করিনি" - এই কারণেই আমি প্রশ্নটি প্রথম স্থানে জিজ্ঞাসা করেছি। আমি আশা করি না যে জিসিসি কোনও কৌশল আঁকবে।
রহস্যময়

1

এমনকি যদি কোনও সংকলক সেই পূর্ণসংখ্যার ওভারফ্লোটিকে অবশ্যই অপরিজ্ঞাত আচরণের একটি "অ-সমালোচক" রূপ হিসাবে বিবেচনা করতে হবে (আনেক্সেক্স এল সংজ্ঞায়িত), একটি পূর্ণসংখ্যার অতিরিক্ত প্রবাহের ফলাফলটি আরও নির্দিষ্ট আচরণের একটি নির্দিষ্ট প্ল্যাটফর্ম প্রতিশ্রুতি অনুপস্থিত থাকা উচিত, সর্বনিম্ন "আংশিক-অনির্দিষ্ট মান" হিসাবে বিবেচিত। এই বিধিগুলির অধীনে, 1073741824 + 1073741824 যুক্ত করা নির্বিচারে 2147483648 বা -2147483648 বা 2147483648 Mod 4294967296 এর সাথে সংগৃহীত অন্য কোনও মান হিসাবে বিবেচিত হতে পারে, এবং সংযোজন দ্বারা প্রাপ্ত মানগুলি নির্বিচারে 0 মান 42949676 অনুসারে মান হিসাবে গণ্য হতে পারে।

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

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.