লিনাক্সে স্ট্যাক বরাদ্দ কীভাবে কাজ করে?


18

ওএস কি স্ট্যাক বা অন্য কিছুর জন্য স্থির পরিমাণের বৈধ ভার্চুয়াল স্থান সংরক্ষণ করে? আমি কি কেবল বড় স্থানীয় ভেরিয়েবলগুলি ব্যবহার করে একটি স্ট্যাক ওভারফ্লো উত্পাদন করতে সক্ষম?

আমি Cআমার অনুমানটি পরীক্ষা করার জন্য একটি ছোট প্রোগ্রাম লিখেছি । এটি X86-64 CentOS 6.5 এ চলছে।

#include <string.h>
#include <stdio.h>
int main()
{
    int n = 10240 * 1024;
    char a[n];
    memset(a, 'x', n);
    printf("%x\n%x\n", &a[0], &a[n-1]);
    getchar();
    return 0;
}

প্রোগ্রাম রানিং দেয় &a[0] = f0ceabe0এবং&a[n-1] = f16eabdf

প্রকল্পের মানচিত্রগুলি স্ট্যাকটি দেখায়: 7ffff0cea000-7ffff16ec000. (10248 * 1024B)

তারপরে আমি বাড়ানোর চেষ্টা করেছি n = 11240 * 1024

প্রোগ্রাম রানিং দেয় &a[0] = b6b36690এবং&a[n-1] = b763068f

প্রকল্পের মানচিত্রগুলি স্ট্যাকটি দেখায়: 7fffb6b35000-7fffb7633000. (11256 * 1024B)

ulimit -s10240আমার পিসিতে মুদ্রণ ।

আপনি দেখতে পাচ্ছেন, উভয় ক্ষেত্রেই স্ট্যাকের আকারটি যা ulimit -sদেয় তার চেয়ে বড় । এবং স্ট্যাক বড় স্থানীয় ভেরিয়েবলের সাথে বৃদ্ধি পায়। স্ট্যাকের শীর্ষটি কোনওভাবে 3-5 কেবি আরও বন্ধ &a[0](এএফআইএইচ রেড জোনটি 128 বি)।

তাহলে এই স্ট্যাক মানচিত্রটি কীভাবে বরাদ্দ পাওয়া যায়?

উত্তর:


14

দেখা যাচ্ছে স্ট্যাকের মেমরির সীমা বরাদ্দ করা হয়নি (যাইহোক, এটি সীমাহীন স্ট্যাকের সাথে পারেনি)। https://www.kernel.org/doc/Docamentation/vm/overcommit-accounting বলেছেন:

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

তবে স্ট্যাকের এমএম্যাপিং করা একটি সংকলকের লক্ষ্য হবে (যদি এর জন্য এটির বিকল্প থাকে)।

সম্পাদনা: একটি x84_64 দেবিয়ান মেশিনে কিছু পরীক্ষার পরে, আমি দেখতে পেয়েছি যে স্ট্যাকটি কোনও সিস্টেম কল ছাড়াই বৃদ্ধি পায় (অনুযায়ী strace)। সুতরাং, এর অর্থ হ'ল কার্নেলটি স্বয়ংক্রিয়ভাবে এটি বৃদ্ধি করে (উপরে "অন্তর্নিহিত" এর অর্থ এটি), অর্থাত্ প্রক্রিয়াটি ছাড়াই mmap/ ছাড়াই mremap।

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

লিনাক্স মেমরি পরিচালনা সম্পর্কিত অন্যান্য উল্লেখ (তবে স্ট্যাক সম্পর্কে প্রায় কিছুই নেই):

সম্পাদনা 2: এই বাস্তবায়নের একটি ত্রুটি রয়েছে: কোণার ক্ষেত্রে, স্ট্যাক-হিপ সংঘর্ষ সনাক্ত করা যায় না, এমনকি যেখানে স্ট্যাক সীমাটির চেয়েও বড় হবে! কারণটি হ'ল স্ট্যাকের একটি ভেরিয়েবলের লেখার বরাদ্দ হ্যাপ মেমোরিতে শেষ হতে পারে, যেখানে কোনও পৃষ্ঠা ত্রুটি নেই এবং কার্নেল জানতে পারে না যে স্ট্যাকটি প্রসারিত করার দরকার ছিল। আলোচনায় আমার উদাহরণটি দেখুন জিএনইউ / লিনাক্সের অধীনে সাইলেন্ট স্ট্যাক-হিপ সংঘর্ষ আমি সিসিপি-সহায়তা তালিকায় শুরু করেছি। এটি এড়াতে, সংকলকটির ফাংশন কলে কিছু কোড যুক্ত করা প্রয়োজন; এটি -fstack-checkজিসিসির জন্য করা যেতে পারে (বিশদ বিবরণের জন্য আয়ান ল্যান্স টেলরের জবাব এবং জিসিসির ম্যান পৃষ্ঠা দেখুন)।


এটি আমার প্রশ্নের সঠিক উত্তর বলে মনে হচ্ছে। তবে এটি আমাকে আরও বিভ্রান্ত করে। কখন ম্রেম্যাপ কলটি ট্রিগার হবে? এটি কি প্রোগ্রামটিতে নির্মিত একটি সাইকাল হবে?
— আমোস

@ এমোস আমি ধরে নিয়েছি যে কোনও ফাংশন কল এলে বা বরাদ্দ () কল করার সময় প্রয়োজনে ম্রেম্যাপ কলটি ট্রিগার হবে।
— ভিঙ্ক 17

যারা জানেন না তাদের জন্য এমএমএপ কী তা সম্ভবত উল্লেখ করা ভাল ধারণা হবে।
— ফাহিম মিঠা

@ ফাহিমমিঠা আমি কিছু তথ্য যুক্ত করেছি। যারা এমএমএপ কি জানেন না তাদের জন্য, উপরে উল্লিখিত মেমরি FAQ দেখুন। এখানে, স্ট্যাকের জন্য এটি "বেনামে ম্যাপিং" হত যাতে অব্যবহৃত স্থান কোনও শারীরিক স্মৃতি গ্রহণ না করে, তবে মেল গোরম্যানের ব্যাখ্যা অনুসারে, কার্নেল একই সাথে ম্যাপিং (ভার্চুয়াল মেমরি) এবং শারীরিক বরাদ্দ দেয় ।
— ভিঙ্ক 17

1
@ ম্যাক্স আমি ওপি'র ulimit -sশর্ত অনুসারে 10240 প্রদানের মাধ্যমে ওপি'র প্রোগ্রামটি চেষ্টা করেছি এবং প্রত্যাশার সাথে সাথে আমি একটি সিএসএসইজিভি পাই (এটিই পসিক্স দ্বারা প্রয়োজনীয়: "যদি এই সীমা অতিক্রম করা হয়, তবে থ্রেডের জন্য সিগসাইজিভি তৈরি করা হবে)। ")। আমি ওপির কার্নেলের মধ্যে একটি বাগ সন্দেহ করি।
— ভিঙ্ক

6

লিনাক্স কার্নেল ৪.২

সর্বনিম্ন পরীক্ষা প্রোগ্রাম

এরপরে আমরা এটি একটি ন্যূনতম NASM -৪-বিট প্রোগ্রাম দিয়ে পরীক্ষা করতে পারি:

global _start
_start:
    sub rsp, 0x7FF000
    mov [rsp], rax
    mov rax, 60
    mov rdi, 0
    syscall

নিশ্চিত হয়ে নিন যে আপনি ASLR বন্ধ করেছেন এবং পরিবেশের ভেরিয়েবলগুলি সরিয়ে ফেলুন কারণ সেগুলি স্ট্যাকের মধ্যে যাবে এবং স্থান গ্রহণ করবে:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
env -i ./main.out

সীমাটি আমার ulimit -s( আমার জন্য 8MiB) থেকে কিছুটা নিচে । দেখে মনে হচ্ছে এটি অতিরিক্ত সিস্টেম ভি নির্দিষ্টকরণের কারণে প্রথমে পরিবেশ ছাড়াও স্ট্যাকের উপরে রাখে: লিনাক্স Assembly৪ কমান্ড লাইন প্যারামিটারগুলি সমাবেশে | স্ট্যাক ওভারফ্লো

আপনি যদি এই বিষয়ে গুরুতর হন তবে টুডো একটি ন্যূনতম আরআরডি চিত্র তৈরি করুন যা স্ট্যাক শীর্ষ থেকে লেখা শুরু করে নীচে যায় এবং তারপরে এটি QEMU + GDB দিয়ে চালান । dprintfস্ট্যাকের ঠিকানাটি মুদ্রণ করে একটি লুপ রেখে দিন এবং একটি ব্রেকপয়েন্ট acct_stack_growth। এটি গৌরব হবে।

সম্পর্কিত:


2

ডিফল্টরূপে, সর্বাধিক স্ট্যাকের আকারটি প্রতি প্রক্রিয়া অনুসারে 8 এমবি হিসাবে কনফিগার করা হয়েছে,
তবে এটি ব্যবহার করে এটি পরিবর্তন করা যেতে পারে ulimit:

কেবিতে ডিফল্ট দেখাচ্ছে:

$ ulimit -s
8192

সীমাহীনতে সেট করুন:

ulimit -s unlimited

বর্তমান শেল এবং সাবহেলগুলি এবং তাদের শিশু প্রক্রিয়াগুলিকে প্রভাবিত করছে।
( ulimitশেল বিল্টিন কমান্ড)

আপনি
cat /proc/$PID/maps | grep -F '[stack]'
লিনাক্সে : এর সাথে ব্যবহারের জন্য প্রকৃত স্ট্যাক ঠিকানার পরিসরটি প্রদর্শন করতে পারেন ।


সুতরাং যখন কোনও প্রোগ্রাম বর্তমান শেল দ্বারা লোড হয়, ওএস প্রোগ্রামের জন্য কেবি'র একটি মেমরি বিভাগকে ulimit -sবৈধ করে তুলবে । আমার ক্ষেত্রে এটি 10240KB। তবে যখন আমি একটি স্থানীয় অ্যারে ঘোষণা করি char a[10240*1024]এবং সেট করি a[0]=1, প্রোগ্রামটি সঠিকভাবে প্রস্থান করে। কেন?
— আমোস

শেষ উপাদানটিও সেট করার চেষ্টা করুন। এবং নিশ্চিত করুন যে সেগুলি অপ্টিমাইজড না হয়ে গেছে।
— ভিঙ্ক 17

@ এমোস আমি ভিনক 17 এর অর্থ কী তা হ'ল আপনি এমন একটি মেমরি অঞ্চলটির নাম দিয়েছেন যা আপনার প্রোগ্রামের স্ট্যাকের সাথে খাপ খায় না , তবে আপনি যে অংশটি ফিট করেন না বাস্তবে এটি অ্যাক্সেস করেন না , মেশিনটি কখনই এটি লক্ষ্য করে না - এটি না এমনকি তথ্য পেতে ।
— ভোলকার সিগেল

@ আমোস চেষ্টা করুন int n = 10240*1024; char a[n]; memset(a,'x',n);... সেগ ত্রুটি
— গোল্ডলোকস

2
@ আমোস সুতরাং, আপনি দেখতে পাচ্ছেন যে a[]আপনার 10 এমবি স্ট্যাকের বরাদ্দ দেওয়া হয়নি। সংকলকটি হয়ত দেখেছিল যে কোনও পুনরাবৃত্ত কল হতে পারে না এবং বিশেষ বরাদ্দ দেওয়া হতে পারে, বা অন্য কিছু যেমন একটি বিচ্ছিন্ন স্ট্যাক বা কিছু দিকনির্দেশনা।
— ভিঙ্ক 17
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.