git logo

معرفی سایت oh shit git

گیت، معروف ترین و پر استفاده ترین VCS یا همون سیستم مدیریت نسخه در حال حاضر هست. تقریبا توی هر شرکت معقولی که تصمیم بگیرید کار کنید باید گیت رو بلد باشید.

git logo


یک از مشکلاتی که اغلب اوقات موقع کار کردن با گیت براتون پیش میاد این هست که اشتباهی کار رو انجام می‌دید و استرس می‌گیرید که چطوری می‌تونید کاری که کردید رو برگردونید.
خب اولین راه حل همیشه اینجور مواقع سرچ کردن مسئله داخل گوگل هست اما اگر این کار رو کرده باشید میدونید که بعضی اوقات پیدا کردن راه حل از داخل اینترنت هم کار سختی هست.

نویسنده وبسایت oh shit git اومده چنتا از مشکلاتی که معمولا توی کار با گیت پیش میان رو اونجا نوشته و راه حل شون رو هم گفته.
نگاه کردنشون جالبه، شاید روزی مشکلی رو حل کنند

Arpanet پدربزرگ اینترنت فعلی

Arpanet اولین شبکه پکت سوئیچ گسترده، که به شکل توزیع شده کنترل می‌شد و جزو اولین شبکه هایی بود که از tcp/ip استفاده می‌کرد.
این شبکه توسط آرپا (ARPA) که میشه Advanced Research Projects Agency که زیر مجموعه ای از سازمان دفاع آمریکا محسوب میشه بوجود اومد و به مرور بزرگ شد تا تبدیل شد به اینترنتی که امروز داریم.
توی عکس های زیر می‌تونید مراحل تبدیل شدن یک ایده‌ی ساده و اولیه و تبدیل اون به شبکه آرپا رو ببینید. اگر عکس های بیشتر رو می‌خواید به اینجا سر بزنید.

ARPANET in 1969

ARPANET in 1977

چرا من از لینوکس استفاده می‌کنم : اتوماتیک کردن کارهام

امروز تصمیم گرفتم یکسری پست داخل وبلاگ داشته باشم که توی اون ها توضیح بدم که چرا از لینوکس استفاده میکنم و چجوری توی کار هام بهم کمک می‌کنه .
این اولین پست از این مجموعه پست ها هست و قراره توضیح بدم که لینوکس چطوری توی رزرو غذای دانشگاه بهم کمک می‌کنه.

الان که دارم این پست رو می‌نویسم دانشجوی ترم دو ارشد هستم و این اولین ترمی هست که بعد از تموم شدن کرونا داره به شکل حضوری برگزار میشه.
اینجا برای رزرو غذای هفته بعد باید یک هفته زودتر غذاتون رو رزرو کنید و اگر تا ساعت ۲ بعد از ظهر روز چهارشنبه هفته جاری غذایی رزرو نکنید، هفته بعد کاملا بدون غذا میمونید و باید غذای روزفروش بگیرید که قیمتش چند برابر غذای رزروی هست و عملا برای یک دانشجو نمی‌ارزه 🙂
من رزرو غذام رو هیچ وقت فراموش نمی‌کنم اما الان به ذهنم رسید خوبه که هر هفته یک ایمیل هم به شکل خودکار برام ارسال بشه که این رو بهم یاد‌آوری کنه .این کار هم باعث میشه چیز های جدید یاد بگیرم و هم خغن تره .

کاری که می‌خوام بکنم این هست که به شکل خودکار هر هفته روز های یکشنبه ساعت ۸ شب که تقریبا مطمئنم سیستمم روشنه یک ایمیل برام بیاد که رزرو غذا رو بهم یاد آوری کنه. البته اگر سیستمم هم خاموش باشه مشکلی نیست و راه حلش استفاده از anacron هست ولی من اینجا از اون استفاده نمی‌کنم

برای این کار به دوتا چیز نیاز دارم :
۱- اول اینکه بتونم یک ایمیل ارسال کنم
۲- بتونم این کار رو به شکل خودکار توی ساعت و روز خاصی انجام بدم

برای مورد اول از ترمینال لینوکس استفاده می‌کنم و با استفاده از آدرس ایمیل خودم به خودم ایمیل می‌زنم . اگر نمی‌دونید که چطوری از ترمینال ایمیل بفرستید کافیه مراحلی که اینجا گفته شده رو دنبال کنید .
برای قسمت دوم هم از cron job داخل لینوکس استفاده می‌کنم
cron job ها داخل لینوکس این امکان رو به ما میدن که بتونیم یکسری کار ها رو داخل زمان های مشخصی به شکل schedule انجام بدیم مثلا بهش بگیم که هر هفته ساعت ۲ شب که همه خوابن یک بکاپ از سیستم بگیر و اون رو روی هارد فلان با اسم و تاریخ فلان ذخیره کن.

خب اول یک برنامه یک خطی می‌نویسم و توی فایلی به نام food_reserve.sh ذخیره می‌کنم
کد برنامه میگه که یک ایمیل با متن reserve your food otherwise you have egg و موضوع Reserve Food برای ایمیل من که sinasoheili79[at]gmail.com هست ارسال کن

#!/bin/sh

echo "reserve your food otherwise you have egg" | mail -s "Reserve Food" sinasoheili79@gmail.com

حالا باید به cron بگیم که این فایل رو هر یکشنبه ساعت 8 شب که میشه ساعت 20 اجرا کن . برای این کار دستور crontab -e رو اجرا میکنم و محتوای فایلی که باز میشه رو به شکل زیر تغییر میدم

# m h  dom mon dow   command
  0 20   *   *   0    ~/bin/./food_email.sh

اگر براتون سوال هست که چرا مقدار dow رو 0 گذاشتم دلیلش این هست که خارجی ها روز اول هفتشون دو شنبه هست و توی کامپیوتر ما از 0 شروع می‌کنیم به شمردن پس روز یکشنبه رو باید 0 در نظر بگیریم. اگر برای مشخص کردن زمان داخل crontab شک دارید می‌تونید از این استفاده کنید.

پی‌نوشت : مسلما راه های ساده‌تری مثل استفاده از تقویم یا برنامه های reminder هم هست ولی من ترجیح میدم از این روش استفاده کنم چون باعث میشه با پیاده کردن همین برنامه ساده چیز های جدید یادبگیرم


حمله درب پشتی از طریق کامپایلر

حمله‌ی درب پشتی از طریق کامپایلر یا Compiler backdoor attack یکی از حمله هایی است که هنوز به شکل رسمی روشی برای جلوگیری از آن معرفی نشده است
توی این پست روش کار این حمله رو توضیح میدم و سعی میکنم اون رو برای کامپایلر زبان C پیاده کنم.

معرفی

کن تامسون، برنامه نویس سیستم عامل یونیکس در سال 1984 در مراسم Turing Award داخل سخنرانیش حمله درب پشتی از طریق کامپایلر رو معرفی و در موردش صحبت می‌کنه.
در سال 2015 نرم افزار XcodeGhost که برای ساخت برنامه های شرکت اپل از اون استفاده می‌شده از همین تکنیک استفاده می‌کرده و گفته میشه که این اولین حمله در مقیاس بزرگ برای اپ استور اپل بوده و باعث شده بیش از 4000 برنامه داخل فروشگاه اپل آلوده بشه.
همانطور که از اسم حمله هم مشخصه، کامپایلر شما زمانی که می‌خواهد کد شما رو کمپایل کنه بدون سر و صدا یک در پشتی رو داخل کد های شما ایجاد میکنه
شما هم که از این درب پشتی خبر ندارید پس برنامه خودتون رو منتشر می‌کنید و این شروع ماجراست. .

چرا این حمله مهمه ؟

برای جواب دادن به این سوال نیاز هست که کمی عمیق تر به مشکل نگاه کنیم.
بذارید اینجوری شروع کنیم که اصلا از کجا می‌تونیم مطمئن باشیم که کامپایلری که الان ازش استفاده می‌کنیم توی برنامه هامون درب پشتی درست نمیکنه ؟
احتمالا جواب این هست که خب کد های مربوط به کامپایلر به شکل open source هست و اگر چنین مشکلی وجود داشته باشه حتما هستند کسایی که اون کد رو بخونن و متوجه چنین مشکلی بشن.
حالا سوال جدید این هست که اگر فرض کنیم کد مربوط به کامپایلر منبع باز باشه و کسی هم باشه که اون کد رو کنترل کنه و بخونه، کد مربوط به خود کامپایلر نیاز داره که توسط یک کامپایلر دیگه کامپایل بشه و ما چطوری می‌تونیم مطمئن بشیم که اون کامپایلر، درب پشتی رو داخل کامپلر اول ایجاد نمی‌کنه ؟
ممکنه بگید که خب می‌تونیم از یک disassembler استفاده کنیم و چک کنیم که فایل های اجرایی کامپایلر ما کد مخربی داخلشون نباشه.
اما این روش هم جوابگو نیست چون disassembler هم در نهایت یک برنامه است و ممکنه خود این برنامه هم رفتار بدی از خودش نشون بده و زمانی که می‌خواهد کد های مربوط به کامپایلر رو برای ما ایجاد کنه، کد های بد رو در داخل سورس کد مخفی کنه و نمایش نده.
ممکنه دوباره در جواب بگید که خب این روش خیلی سخته و ممکنه اصلا کسی سراغ عملی کردن این مسئله نره و در جواب باید بگم که ساخت این کامپایلر خیلی ساده تر از اون چیزی هست که فکر می‌کنید و در ادامه نشون میدم که چطور توی کمتر از ۱۰۰ خط کد این کامپایلر رو میشه ساخت.

ساخت کامپایلر

برای نشان دادن این حمله من از این ریپوزیتوری استفاده می‌کنم.
برای شروع بیاید نگاهی به فایل Login.cpp بندازیم. توی این فایل برنامه ی ساده ای هست که میگه اگر کاربر رمز ورود رو test123 بزنه می‌تونه وارد بشه

#include <iostream>

using namespace std;

int main() {
    cout << "Enter password:" << endl;
    string enteredPassword;
    cin >> enteredPassword;
    if(enteredPassword == "test123")    
        cout << "Successfully logged in as root" << endl;
    else
        cout << "Wrong password, try again." << endl;
}

حالا بیایید این برنامه رو با استفاده از کامپایلری که داریم کامپایل کنیم. پس داخل ترمینال کد زیر رو می‌زنیم

./Compiler Login.cpp -o Login

حالا اگر کد کامپایل شده‌ی برنامه رو اجرا کنیم و به جای رمز ورورد backdoor رو بزنیم می‌بینیم که برنامه این پسورد رو درست تشخیص می‌ده و وارد می‌شه.
اما همونطور که داخل کد می‌بیندی ما فقط پسورد test123 رو قبول می‌کنیم.
احتمالا حدس میزنید که شاید مشکل از کامپایلری باشه که استفاده کردیم، پس بیاید نگاهی هم به سورس کد کامپایلر بندازیم.

#include <string>
#include <cstdlib> 

using namespace std;

int main(int argc, char *argv[]) {
    string allArgs = "";
    for(int i=1; i<argc; i++)
        allArgs += " " + string(argv[i]);
    string shellCommand = "g++" + allArgs;
    system(shellCommand.c_str());
}

همونطور که داخل کد هم مشخصه این کد از کامپایلر ++g استفاده ‌میکنه و فایل ما رو کامپایل می‌کنه
توی این کد هم مشکلی نیست پس چطوری این درب پشتی به کد ما اضافه می‌شه.

قبل از اینکه در مورد اضافه شدن درب پشتی به کد حرف بزنم خوبه که با اصطلاح self-hosting آشنا بشیم
اگر دفت کرده باشید کد کامپایلر ما خودش به زبان C نوشته شده و فایل اجرایی کامپایلر ما می‌تونه فایل برنامه خودش رو هم کامپایل کنه.
مثلا داخل کد زیر من کد برنامه کامپایلرم رو با فایل اجرایی همون کامپایلر، کامپایل می‌کنم.

./Compiler Compiler.cpp -o newCompiler

این به این معنا هست که برای کامپایل کردن سورس کد ورژن جدید کامپایلرمون می‌تونیم از ورژن های قبلی خودش استفاده کنیم.
زبان های دیگه ای هم مثل C++ ، Java و یا python هم این ویژگی رو دارند
جلوتر در مورد اینکه این ویژگی چه تاثیری داره صحبت می‌کنم اما حالا بیایید در مورد اینکه درب پشتی چطور به کد اضافه می‌شه صحبت کنیم.
زمانی که شما فایل Login.cpp رو کامپایل می‌کنید اتفاق های زیر داخل کامپایلر می‌افته:
1- فایل Login.cpp داخل یک فایل موقت به نام LoginWithBackdoor.cpp کپی می‌شود.
2- فایل LoginWithBackdoor.cpp به اون شکلی که می‌خوایم اصلاح میشه. مثلا یک کلمه عبور جدید به اون اضافه می‌شه.
3- فایل LoginWithBackdoor.cpp به جای فایل Login.cpp کامپایل میشه
4- در نهایت فایل LoginWithBackdoor.cpp پاک میشه
اگر به فایل EvilCompiler.cpp نگاه کنیم می‌تونید این مراحل رو ببینید

اما کسی از این کامپایلر استفاده نمی‌کنه چون با خوندن سورس کد ‌مربوط به EvilCompiler.cpp متوجه این مشکل می‌شه پس باید راهی پیدا کنیم که این مشکل رو هم حل کنه. برای حل این مشکل از self-hosting استفاده ‌می‌کنیم.

مخفی کردن ساخت درب پشتی در کامپایلر

فرض کنید کسی برای اطمینان از درست عمل کردن کامپایلر، سورس کد های کامپایلر را دانلود کند و بخواهد خودش آن را کامپایل و از ان استفاده کند.
در این حالت اگر سورس کد EvilCompiler.cpp رو به کاربر بدیم ، کاربر متوجه حمله ما میشه و اگر سورس کد Compiler.cpp رو به کاربر بدیم دیگه درب پشتی به وجود نمیاد

برای رفع این مشکل باید از خاصیت self-hosting استفاده کنیم.
کاربر زمانی که می‌خواهد سورس کد کامپایلر رو کامپایل کنه نیاز به یک کامپایلر داره. ما ( در نقش طراح حمله ) می‌تونیم سورس کد Compiler.cpp رو به عنوان اولین کامپایلر ساخته شده برای این زبان به کاربر نشون بدیم ولی فایل اجرایی EvilCompiler.cpp به عنوان اولین کامپایلر به کاربر داده بشه. در نتیجه هر بار که کاربر سورس کد Compiler.cpp رو با این فایل اجرایی کامپایل کنه، همون روش اضافه کردن درب پشتی تکرار می‌شه و درب پشتی به کامپایلر اضافه می‌شه.

عکس زیر کل این روش رو به خوبی نشون می‌ده :

استفاده از هش برای کشف درب پشتی

یکپارچه بودن اطلاعات یعنی کسی اطلاعات رو در حین انتقال تغییر نده و چیزی که توی مقصد تحویل می‌گیریم دقیقا همون چیزی باشه که در مبدا ارسال شده.
یکی از روش های مرسومی که این روز ها برای چک کردن بکپارچه بودن اطلاعات استفاده می‌شه هش هست. توی این روش فرسنتده‌ی اطلاعات، یک هش رو هم که هش اون اطلاعات هست در اختیار گیرنده قرار میده و با این روش گیرنده با هش کردن اطلاعات دریافتی و مقایسه کردن این دو تا هش با هم میتونه چک کنه آیا اطلاعات تغییر کردن یا نه.
مثلا وقتی که فایل ایزو اوبونتو رو دانلود می‌کنید هش اون هم همراهش به شما نشون داده می‌شه که می‌تونید با هشی که خودتون از فایل ایزو می‌گیرید مقایسه کنید.
اما باید حواسمون باشه که برنامه ای که هش رو برای ما محاسبه میکنه خودش ممکنه یک درب پشتی داشته باشه. اگر به نظرتون چنین چیزی خیلی عجیب، غیر ممکن و یا سخت هست کافیه به این فکر کنید که از gcc که معروف ترین کامپایلر برای زبان C هست برای کامپایل کردن خود gcc و sha256 استفاده میشه.

و اما درسی که ما می‌گیریم …

همانطور که دیدید حمله compiler backdoor attack حمله بسیار جالب و هوشمندانه ای محسوب میشه.
اما این حمله دو نکته مهم رو به ما یاد میده :
۱- به هیچ کدی که توسط شما نوشته و ایجاد نشده باشه نمیشه اعتماد کرد
2- هر چه به سمت لایه های پایین تر کامپیوتر ها و برنامه ها پیش میریم پیدا کردن باگ ها و درب های پشتی و .. سخت تر میشه

اگر توضیحات اضافه تری در مورد این حمله می‌خواید می‌تونید به منبع سر بزنید

در نام گذاری از واحد استفاده کنید !!

نوشتن کد تمیز یکی از مهمترین مهارت هایی هست که هر برنامه نویسی باید حتما به اون توجه کنه. کد تمیز اصطلاح عامی به حساب میاد و به جنبه های مختلفی توی کد نویسی اشاره داره . از ظاهر کد گرفته تا نام گذاری متغیر ها و نوشتن کامنت داخل کد و غیره.
این مهارت به مرور زمان و قدم به قدم تقویت میشه و به نظر من بهترین روش یادگرفتنش این هست که چند وقت یکبار یکی از تکنیک هاش رو یاد بگیرید و سعی کنید از اون لحظه به بعد اون تکنیک رو داخل کد هاتون استفاده کنید.

مشکل کجاست ؟
به کد های زیر که به زبان های پایتون، جاوا و هسکل نوشته شدند نگاه کنید.
همه این  کد ها یک کار رو انجام می‌دهند یعنی سیستم رو برای یک مدت زمانی به تعلیق در میارن یا به عبارت دیگه از نظر زمانی توی اجرای برنامه تاخیر ایجاد می‌کنند. ظاهر کد که خیلی خوب و سادس ولی مشکل کجاست ؟‌

time.sleep(300)
Thread.sleep(300)
threadDelay 300


سوال اصلی این هست که برنامه ما چقدر قراره به حالت تعلیق در بیاد ؟ با توجه به کد های بالا برنامه پایتون برای 5 دقیقه،  برنامه به زبان جاوا برای 0.3 ثانیه و برنامه هسکل برای 0.3 میلی ثانیه به حالت تعلیق در میاد.
چیزی که مشخصه این هست که برنامه های مختلف از  واحد های زمانی مختلف برای کارهاشون استفاده می‌کنند و وقتی کسی کد رو میخونه اگر از قبل اطلاعات نداشته باشه باید بره و مستندات رو بررسی کنه و این یعنی کد به خودی خود خوانا نیست

راه حل چیه؟

۱ – نام گذاری برای آرگومان ها
بعضی از زبان ها مثل پایتون یا کاتلین این امکان رو دارند که بتونیم آرگومان هایی که به یک تابع می‌فرستیم رو به شکل کلید مقدار ارسال کنیم یعنی نام اون آرگومان رو هم کنارش قرار بدیم در نتیجه وقتی می‌خوایم تابع رو فراخوانی کنیم می‌تونیم اسم آرگومان رو کنارش بذاریم که اسم آرگومان، واحد رو هم داخل خودش داره.
یعنی به جای کد زیر

def frobnicate(timeout: int) -> None:
    ...

frobnicate(300)


این کد رو بنویسیم

def frobnicate(*, timeout_seconds: int) -> None:
    # The * forces the caller to use named arguments
    # for all arguments after the *.
    ...

frobnicate(timeout_seconds=300)


برای زبان هایی مثل جاوا هم که چنین امکانی رو ندارند میشه به شکل زیر یک متغیر تعریف کرد و واحد رو داخل اون مشخص کرد

sleep_seconds = 300
time.sleep(sleep_seconds)

۲ – استفاده از نوع داده خاص
راه حل اول همیشه جوابگو نیست چون زبان هایی مثل جاوا این امکان رو ندارن که بشه آرگومان ها رو همراه با اسم ارسال کرد. اما می‌تونیم نوع داده های خودمون رو داشته باشیم. مثلا به حای اینکه ورودی تابع من یک عدد int باشه که نشون دهنده زمان هست، ورودی از نوع کلاسی با عنوان TimeUnit باشه که واحد های زمانی رو داخل خوش مشخص میکنه.
یعنی به جای کد زیر

def frobnicate(timeout: int) -> None:
    ...

frobnicate(300)


از این کد استفاده کنیم

def frobnicate(timeout: timedelta) -> None:
    ...

timeout = timedelta(seconds=300)
frobnicate(timeout)


اما مسئله به اینجا ختم نمیشه و این مشکل نه تنها توی برنامه نویسی بلکه جا های دیگه هم وجود داره مثلا فرض کنید که می‌خواهیم با یک api کار کنیم و اون api جواب زیر رو برای ما ارسال می‌کنه.

{
   "error_code": "E429",
   "error_message": "Rate limit exceeded",
   "retry_after": 100,
}



راه حل هایی که گفته شد برای این موارد هم کاربرد داره مثلا برای این مورد می‌تونیم جواب رو به این شکل برگردونیم.

{
   "error_code": "E429",
   "error_message": "Rate limit exceeded",
   "retry_after_seconds": 100,
}


یا مثلا داخل فایل های کانفیگ برنامه ها ممکنه به چنین مواردی بر بخورید

request_timeout = 10



که بهتر هست به یکی از شکل های زیر تغییر کنند

request_timeout = 10s
request_timeout_seconds = 10


در نهایت این رو یادمون باشه که کدی خوبه که آدم های دیگه هم بتونن اون رو بخونن و هر چی کد های ساده تری رو بنویسیم برنامه نویس بهتری هستیم. کد های پیچیده  نوشتن نه تنها خفن بودن آدم ها رو نشون نمیده بلکه باعث میشه کم کم از بازی حذف بشیم و کسی دوست نداشته باشه باهامون کار کنه یا داخل پروژه هامون مشارکت کنه
منبع

باگ در !Hello World

میشه گفت اولین برنامه ای که هر برنامه نویسی نوشته Hello World هست. توی این برنامه شما فقط یک متن ساده رو داخل خروجی چاپ می‌کنید. اما چطوری ممکنه ی برنامه به این سادگی باگ داشته باشه ؟!

خب ، اول این رو بگم که توی زبان های مختلف این برنامه رو میشه به شکل های مختلفی نوشت مثلا توی زبانی مثل C یا C++ شما می‌تونید به چندین روش اون رو بنویسید. یکی از استاندارد ترین روش ها برای نوشتن این برنامه به زبان C کد زیر هست :

Hello World in C

اما هر چقدر هم که استاندارد بنویسیم باز هم این برنامه باگ داره 🙂
قبل از اینکه در مورد باگ این برنامه حرف بزنیم بیایید کمی با امکانات لینوکس آشنا بشیم.

dev/full/
توی لینوکس هر چیزی یا فایل هست یا پروسس. یکسری فایل هم داریم که واقعا فایل نیستن که بهشون میگیم device file مثل فایل های /dev/null و یا /dev/full.
فایل /dev/null مثل یک چاه هست که هیچ وقت پر نمیشه و هر چیزی که لازمش نداریم مثلا خروجی یک برنامه یا وارنینگ های یک برنامه رو داخلش میریزیم. فایل /dev/full برعکس dev/null/ ، فایلی هست که کاملا پر شده و شما نمی‌تونید داده ی جدیدی رو داخلش بنویسید. گاهی اوقات برای اینکه ببینیم برنامه ما IO stream ها رو به درستی مدیریت میکنه ازش استفاده می‌کنیم مثلا میخواهیم تست کنیم که آیا برنامه من زمانی که یک فایل پر شده می‌تونه به کار خودش ادامه بده و مشکلش رو حل کنه یا نه از این فایل برای تست استفاده میکنیم.
مثلا توی عکس زیر من یک متن رو داخل ترمینال چاپ کردم و خروجیش رو داخل این فایل ریختم و همونطور که می‌بینید بهم ارور داده که فضای کافی نداره.

?$
اگر به خط آخر مربوط به برنامه Hello World که بالا تر بود نگاه کنید می‌بینید که توی خط آخر از ‌return استفاده کردم. معنی این return این هست که اگر برنامه با موفقیت اجرا شد و به درستی به اتمام رسید مقداری که داخل EXIT_SUCCESS هست رو بهم برگردون و اگر موفق نبود خودش کد اروری که اتفاق افتاده رو برمیگردونه.
پس اگر قراره من بدونم که برنامم درست اجرا شده یا نه باید ببینم که چه مقداری رو بر میگردونه. توی لینوکس اگر بخواهیم مقدار بازگشتی برنامه رو بدونیم از ?$ استفاده میکنیم که یک متغیر هست و وضعیت خروج آخرین برنامه رو ذاخل خودش داره .
مثلا برنامه ای که توی تصویر بالا اجرا کردم به ارور خورد و حالا اگر بخواهم که مقدار بازگشتی این برنامه رو ببینم به این روش عمل میکنم :

دستور echo متنی رو روی صفحه کنسول من چاپ میکنه و همونطور که می‌بینید عدد 1 رو به من نشون میده که یعنی آخرین برنامه ای که اجرا کردی به ارور خورده و به درستی به اتمام نرسید. اگر 0 برگردونه یعنی برنامه به درستی اجرا و به اتمام رسیده.

باگ برنامه کجاست ؟ ‌
بیاید با چیز هایی که تا اینجا دیدیم برنامه Hello World رو اجرا کنیم.
من اول برنامه رو کمپایل می‌کنم ، اجراش میکنم و خروجیش رو داخل فایل /dev/full میریزم و بعد هم مقدار بازگشتی برنامه رو چک میکنم :

مشکل رو می‌بینید ؟ من انتظار داشتم که برنامه به من ارور بده و عدد 1 رو برگردونه چون فایل /dev/full  پر هست و نباید بشه چیزی رو داخلش نوشت اما خروجی چیز دیگه ای رو میگه.

مشکل کجاست ؟
بیایید ی نگاهی هم به سیستم کال ها یا همون فراخوانی های سیستمی کنیم. برای این کار توی لینوکس از دستور strace استفاده میکنیم

اگر نگاه کنید توی سمت راست اروری که ما میخواستیم وجود داره یعنی سیستم عامل این ارور رو تشخیص و گزارش داده ولی برنامه اون رو نادیده گرفته.

چقدر این باگ می‌تونه مشکل ساز بشه ؟
درسته که برنامه ی Hello World برنامه ی ساده ای هست و یک برنامه مهم و قابل استفاده نیست ولی داره همون کاری رو میکنه که یک برنامه واقعی ممکنه انجام بده، یک متن رو داخل خروجی استاندارد می‌نویسه و اون رو داخل یک فایل ریدایرکت میکنه.
فرض کنید فرزند یک پروسس میخواد داده ای رو به این شکل داخل یک فایل بنویسه و اون فایل حجم کافی رو نداره و داده ذخیره نمیشه اما برنامه هم ارور نمیده و والد پروسس هم متوجه ارور نمیشه و به کارش ادامه میده در نتیجه یکسری داده رو از دست میدیم.

توی زبان های دیگه چطور ؟
این باگ توی زبان های دیگه هم وجود داره داخل این لینک از گیت‌هاب می‌تونید لیست شون رو ببینید.

منبع

طرح صیانت تصویب شد

دو روز پیش یعنی 1400/12/3 طرح صیانت به تصویب رسید. این روز ها همه دارن در موردش حرف میزنند اما چیزی که به وضوح مشخصه این هست که این طرح خیلی وقت پیش شروع شده و الان صرفا علنی شده .
اکثریت مردم با این طرح مخالف هستند اما 18 نفر تصمیم گرفتن که موافق باشن  و اجراییش کنند.

اینجا نوشتمش که توی قسمتی از تاریخ باقی بمونه. شاید چند سال دیگه کسی پست های این وبلاگ رو بخونه و براش جالب باشه که توی این برهه از تاریخ مردم در تلاش برای بدست ‌‌آوردن مینموم حقوقشون بودند .

پ.ن : امروز هم 1400/12/5 هست که روسیه به اکراین حمله کرد. عده‌ای معتقدند که این جنگ جهانی سوم هست اما هنوز درگیری ها بین دو کشور وجود داره