اسمارٹ کنٹریکٹس میں بگز تلاش کرنے کے لیے Manticore کا استعمال کیسے کریں
اس ٹیوٹوریل کا مقصد یہ دکھانا ہے کہ اسمارٹ کنٹریکٹس میں خود بخود بگز تلاش کرنے کے لیے Manticore کا استعمال کیسے کیا جائے۔
انسٹالیشن
Manticore کے لیے >= python 3.6 درکار ہے۔ اسے pip کے ذریعے یا docker کا استعمال کرکے انسٹال کیا جاسکتا ہے۔
docker کے ذریعے Manticore
docker pull trailofbits/eth-security-toolboxdocker run -it -v "$PWD":/home/training trailofbits/eth-security-toolboxآخری کمانڈ eth-security-toolbox کو ایک docker میں چلاتا ہے جس کی آپ کی موجودہ ڈائریکٹری تک رسائی ہے۔ آپ اپنے ہوسٹ سے فائلیں تبدیل کر سکتے ہیں، اور docker سے فائلوں پر ٹولز چلا سکتے ہیں
docker کے اندر، چلائیں:
solc-select 0.5.11cd /home/trufflecon/pip کے ذریعے Manticore
pip3 install --user manticoresolc 0.5.11 تجویز کیا جاتا ہے۔
ایک اسکرپٹ چلانا
python 3 کے ساتھ ایک python اسکرپٹ چلانے کے لیے:
python3 script.pyڈائنامک سمبولک ایگزیکیوشن کا تعارف
مختصر طور پر ڈائنامک سمبولک ایگزیکیوشن
ڈائنامک سمبولک ایگزیکیوشن (DSE) پروگرام کے تجزیے کی ایک تکنیک ہے جو اعلیٰ درجے کی سیمانٹک بیداری کے ساتھ اسٹیٹ اسپیس کو تلاش کرتی ہے۔ یہ تکنیک "پروگرام پاتھس" کی دریافت پر مبنی ہے، جسے path predicates کہلانے والے ریاضیاتی فارمولوں کے طور پر پیش کیا جاتا ہے۔ تصوراتی طور پر، یہ تکنیک دو مراحل میں پاتھ پریڈیکیٹس پر کام کرتی ہے:
- یہ پروگرام کے ان پٹ پر پابندیوں کا استعمال کرتے ہوئے تعمیر کیے جاتے ہیں۔
- یہ ایسے پروگرام ان پٹس پیدا کرنے کے لیے استعمال ہوتے ہیں جو متعلقہ پاتھس کو ایگزیکیوٹ کرنے کا سبب بنیں گے۔
یہ نقطہ نظر اس لحاظ سے کوئی غلط مثبت پیدا نہیں کرتا ہے کہ تمام شناخت شدہ پروگرام اسٹیٹس کو ٹھوس ایگزیکیوشن کے دوران ٹرگر کیا جا سکتا ہے۔ مثال کے طور پر، اگر تجزیہ میں کوئی انٹیجر اوور فلو ملتا ہے، تو اس کے دوبارہ پیدا کیے جانے کی ضمانت ہے۔
پاتھ پریڈیکیٹ کی مثال
DSE کیسے کام کرتا ہے اس کی بصیرت حاصل کرنے کے لیے، درج ذیل مثال پر غور کریں:
1function f(uint a){23 if (a == 65) {4 // A bug is present5 }67}چونکہ f() میں دو پاتھس ہیں، اس لیے ایک DSE دو مختلف پاتھ پریڈیکیٹس بنائے گا:
- پاتھ 1:
a == 65 - پاتھ 2:
Not (a == 65)
ہر پاتھ پریڈیکیٹ ایک ریاضیاتی فارمولا ہے جسے SMT solveropens in a new tab نامی ایک نام نہاد کو دیا جا سکتا ہے، جو مساوات کو حل کرنے کی کوشش کرے گا۔ پاتھ 1 کے لیے، سولور کہے گا کہ پاتھ کو a = 65 کے ساتھ تلاش کیا جا سکتا ہے۔ پاتھ 2 کے لیے، سولور a کو 65 کے علاوہ کوئی بھی قدر دے سکتا ہے، مثال کے طور پر a = 0۔
خصوصیات کی تصدیق کرنا
Manticore ہر پاتھ کے تمام ایگزیکیوشن پر مکمل کنٹرول کی اجازت دیتا ہے۔ نتیجے کے طور پر، یہ آپ کو تقریباً کسی بھی چیز پر من مانی پابندیاں شامل کرنے کی اجازت دیتا ہے۔ یہ کنٹرول کنٹریکٹ پر خصوصیات بنانے کی اجازت دیتا ہے۔
درج ذیل مثال پر غور کریں:
1function unsafe_add(uint a, uint b) returns(uint c){2 c = a + b; // no overflow protection3 return c;4}یہاں فنکشن میں تلاش کرنے کے لیے صرف ایک پاتھ ہے:
- پاتھ 1:
c = a + b
Manticore کا استعمال کرتے ہوئے، آپ اوور فلو کی جانچ کر سکتے ہیں، اور پاتھ پریڈیکیٹ میں پابندیاں شامل کر سکتے ہیں:
c = a + b AND (c < a OR c < b)
اگر a اور b کی ایسی ویلیویشن تلاش کرنا ممکن ہے جس کے لیے مذکورہ بالا پاتھ پریڈیکیٹ قابل عمل ہے، تو اس کا مطلب ہے کہ آپ کو ایک اوور فلو مل گیا ہے۔ مثال کے طور پر سولور ان پٹ a = 10 , b = MAXUINT256 پیدا کر سکتا ہے۔
اگر آپ ایک فکسڈ ورژن پر غور کریں:
1function safe_add(uint a, uint b) returns(uint c){2 c = a + b;3 require(c>=a);4 require(c>=b);5 return c;6}اوور فلو چیک کے ساتھ متعلقہ فارمولا ہوگا:
c = a + b AND (c >= a) AND (c=>b) AND (c < a OR c < b)
اس فارمولے کو حل نہیں کیا جا سکتا؛ دوسرے لفظوں میں یہ ایک ثبوت ہے کہ safe_add میں، c ہمیشہ بڑھے گا۔
DSE اس طرح ایک طاقتور ٹول ہے، جو آپ کے کوڈ پر من مانی پابندیوں کی تصدیق کر سکتا ہے۔
Manticore کے تحت چلانا
ہم دیکھیں گے کہ Manticore API کے ساتھ ایک اسمارٹ کنٹریکٹ کو کیسے تلاش کیا جائے۔ ہدف درج ذیل اسمارٹ کنٹریکٹ example.solopens in a new tab ہے:
1pragma solidity >=0.4.24 <0.6.0;23contract Simple {4 function f(uint a) payable public{5 if (a == 65) {6 revert();7 }8 }9}سب دکھائیںایک اسٹینڈ الون ایکسپلوریشن چلائیں
آپ درج ذیل کمانڈ کے ذریعے Manticore کو براہ راست اسمارٹ کنٹریکٹ پر چلا سکتے ہیں (پروجیکٹ ایک Solidity فائل، یا ایک پروجیکٹ ڈائریکٹری ہو سکتا ہے):
$ manticore projectآپ کو اس طرح کے ٹیسٹ کیسز کا آؤٹ پٹ ملے گا (ترتیب بدل سکتی ہے):
1...2... m.c.manticore:INFO: Generated testcase No. 0 - STOP3... m.c.manticore:INFO: Generated testcase No. 1 - REVERT4... m.c.manticore:INFO: Generated testcase No. 2 - RETURN5... m.c.manticore:INFO: Generated testcase No. 3 - REVERT6... m.c.manticore:INFO: Generated testcase No. 4 - STOP7... m.c.manticore:INFO: Generated testcase No. 5 - REVERT8... m.c.manticore:INFO: Generated testcase No. 6 - REVERT9... m.c.manticore:INFO: Results in /home/ethsec/workshops/Automated Smart Contracts Audit - TruffleCon 2018/manticore/examples/mcore_t6vi6ij310...سب دکھائیںاضافی معلومات کے بغیر، Manticore نئے سمبولک ٹرانزیکشنز کے ساتھ کنٹریکٹ کو اس وقت تک تلاش کرے گا جب تک کہ وہ کنٹریکٹ پر نئے پاتھس کو تلاش نہ کر لے۔ Manticore ایک ناکام ٹرانزیکشن کے بعد (مثال کے طور پر: ایک revert کے بعد) نئے ٹرانزیکشنز نہیں چلاتا ہے۔
Manticore معلومات کو ایک mcore_* ڈائریکٹری میں آؤٹ پٹ کرے گا۔ دیگر چیزوں کے علاوہ، آپ کو اس ڈائریکٹری میں ملے گا:
global.summary: کوریج اور کمپائلر وارننگزtest_XXXXX.summary: کوریج، آخری ہدایت، فی ٹیسٹ کیس اکاؤنٹ بیلنسtest_XXXXX.tx: فی ٹیسٹ کیس ٹرانزیکشنز کی تفصیلی فہرست
یہاں Manticore کو 7 ٹیسٹ کیسز ملے ہیں، جو اس کے مطابق ہیں (فائل نام کی ترتیب بدل سکتی ہے):
| ٹرانزیکشن 0 | ٹرانزیکشن 1 | ٹرانزیکشن 2 | نتیجہ | |
|---|---|---|---|---|
| test_00000000.tx | کنٹریکٹ کی تخلیق | f(!=65) | f(!=65) | STOP |
| test_00000001.tx | کنٹریکٹ کی تخلیق | فال بیک فنکشن | REVERT | |
| test_00000002.tx | کنٹریکٹ کی تخلیق | RETURN | ||
| test_00000003.tx | کنٹریکٹ کی تخلیق | f(65) | REVERT | |
| test_00000004.tx | کنٹریکٹ کی تخلیق | f(!=65) | STOP | |
| test_00000005.tx | کنٹریکٹ کی تخلیق | f(!=65) | f(65) | REVERT |
| test_00000006.tx | کنٹریکٹ کی تخلیق | f(!=65) | فال بیک فنکشن | REVERT |
ایکسپلوریشن کا خلاصہ f(!=65) ظاہر کرتا ہے کہ f کو 65 سے مختلف کسی بھی قدر کے ساتھ کال کیا گیا ہے۔
جیسا کہ آپ دیکھ سکتے ہیں، Manticore ہر کامیاب یا واپس کیے گئے ٹرانزیکشن کے لیے ایک منفرد ٹیسٹ کیس تیار کرتا ہے۔
اگر آپ تیز کوڈ ایکسپلوریشن چاہتے ہیں تو --quick-mode فلیگ کا استعمال کریں (یہ بگ ڈیٹیکٹرز، گیس کمپیوٹیشن، ... کو غیر فعال کر دیتا ہے)
API کے ذریعے ایک اسمارٹ کنٹریکٹ میں ہیرا پھیری کرنا
یہ سیکشن Manticore Python API کے ذریعے ایک اسمارٹ کنٹریکٹ میں ہیرا پھیری کرنے کے طریقے کی تفصیلات بیان کرتا ہے۔ آپ python ایکسٹینشن *.py کے ساتھ نئی فائل بنا سکتے ہیں اور اس فائل میں API کمانڈز (جن کی بنیادی باتیں ذیل میں بیان کی جائیں گی) کو شامل کرکے ضروری کوڈ لکھ سکتے ہیں اور پھر اسے $ python3 *.py کمانڈ کے ساتھ چلا سکتے ہیں۔ آپ ذیل میں دی گئی کمانڈز کو براہ راست python کنسول میں بھی ایگزیکیوٹ کر سکتے ہیں، کنسول چلانے کے لیے $ python3 کمانڈ کا استعمال کریں۔
اکاؤنٹس بنانا
سب سے پہلے آپ کو درج ذیل کمانڈز کے ساتھ ایک نئی بلاک چین شروع کرنی چاہیے:
1from manticore.ethereum import ManticoreEVM23m = ManticoreEVM()ایک غیر کنٹریکٹ اکاؤنٹ m.create_accountopens in a new tab کا استعمال کرتے ہوئے بنایا جاتا ہے:
1user_account = m.create_account(balance=1000)ایک Solidity کنٹریکٹ m.solidity_create_contractopens in a new tab کا استعمال کرتے ہوئے تعینات کیا جا سکتا ہے:
1source_code = '''2pragma solidity >=0.4.24 <0.6.0;3contract Simple {4 function f(uint a) payable public{5 if (a == 65) {6 revert();7 }8 }9}10'''11# Initiate the contract12contract_account = m.solidity_create_contract(source_code, owner=user_account)سب دکھائیںخلاصہ
- آپ m.create_accountopens in a new tab اور m.solidity_create_contractopens in a new tab کے ساتھ صارف اور کنٹریکٹ اکاؤنٹس بنا سکتے ہیں۔
ٹرانزیکشنز کو ایگزیکیوٹ کرنا
Manticore دو قسم کے ٹرانزیکشن کو سپورٹ کرتا ہے:
- را ٹرانزیکشن: تمام فنکشنز کو تلاش کیا جاتا ہے
- نامزد ٹرانزیکشن: صرف ایک فنکشن کو تلاش کیا جاتا ہے
را ٹرانزیکشن
ایک را ٹرانزیکشن m.transactionopens in a new tab کا استعمال کرتے ہوئے ایگزیکیوٹ کیا جاتا ہے:
1m.transaction(caller=user_account,2 address=contract_account,3 data=data,4 value=value)ٹرانزیکشن کا کالر، ایڈریس، ڈیٹا، یا ویلیو یا تو ٹھوس یا سمبولک ہو سکتا ہے:
- m.make_symbolic_valueopens in a new tab ایک سمبولک ویلیو بناتا ہے۔
- m.make_symbolic_buffer(size)opens in a new tab ایک سمبولک بائٹ ایرے بناتا ہے۔
مثال کے طور پر:
1symbolic_value = m.make_symbolic_value()2symbolic_data = m.make_symbolic_buffer(320)3m.transaction(caller=user_account,4 address=contract_address,5 data=symbolic_data,6 value=symbolic_value)اگر ڈیٹا سمبولک ہے، تو Manticore ٹرانزیکشن ایگزیکیوشن کے دوران کنٹریکٹ کے تمام فنکشنز کو تلاش کرے گا۔ فنکشن کا انتخاب کیسے کام کرتا ہے، یہ سمجھنے کے لیے Hands on the Ethernaut CTFopens in a new tab مضمون میں فال بیک فنکشن کی وضاحت دیکھنا مددگار ہوگا۔
نامزد ٹرانزیکشن
فنکشنز کو ان کے نام کے ذریعے ایگزیکیوٹ کیا جا سکتا ہے۔
f(uint var) کو ایک سمبولک ویلیو کے ساتھ، user_account سے، اور 0 ایتھر کے ساتھ ایگزیکیوٹ کرنے کے لیے، استعمال کریں:
1symbolic_var = m.make_symbolic_value()2contract_account.f(symbolic_var, caller=user_account, value=0)اگر ٹرانزیکشن کی value کی وضاحت نہیں کی گئی ہے، تو یہ بطور ڈیفالٹ 0 ہے۔
خلاصہ
- ایک ٹرانزیکشن کے آرگومنٹس ٹھوس یا سمبولک ہو سکتے ہیں
- ایک را ٹرانزیکشن تمام فنکشنز کو تلاش کرے گا
- فنکشن کو ان کے نام سے کال کیا جا سکتا ہے
ورک اسپیس
m.workspace وہ ڈائریکٹری ہے جو تمام تیار کردہ فائلوں کے لیے آؤٹ پٹ ڈائریکٹری کے طور پر استعمال ہوتی ہے:
1print("Results are in {}".format(m.workspace))ایکسپلوریشن کو ختم کریں
ایکسپلوریشن کو روکنے کے لیے m.finalize()opens in a new tab کا استعمال کریں۔ ایک بار یہ طریقہ کال ہو جانے کے بعد مزید کوئی ٹرانزیکشن نہیں بھیجا جانا چاہیے اور Manticore ہر تلاش کیے گئے پاتھ کے لیے ٹیسٹ کیسز تیار کرتا ہے۔
خلاصہ: Manticore کے تحت چلانا
پچھلے تمام مراحل کو ایک ساتھ رکھنے پر، ہم حاصل کرتے ہیں:
1from manticore.ethereum import ManticoreEVM23m = ManticoreEVM()45with open('example.sol') as f:6 source_code = f.read()78user_account = m.create_account(balance=1000)9contract_account = m.solidity_create_contract(source_code, owner=user_account)1011symbolic_var = m.make_symbolic_value()12contract_account.f(symbolic_var)1314print("Results are in {}".format(m.workspace))15m.finalize() # stop the explorationسب دکھائیںاوپر دیا گیا تمام کوڈ آپ example_run.pyopens in a new tab میں تلاش کر سکتے ہیں
تھروئنگ پاتھس حاصل کرنا
اب ہم f() میں استثناء پیدا کرنے والے پاتھس کے لیے مخصوص ان پٹس تیار کریں گے۔ ہدف اب بھی درج ذیل اسمارٹ کنٹریکٹ example.solopens in a new tab ہے:
1pragma solidity >=0.4.24 <0.6.0;2contract Simple {3 function f(uint a) payable public{4 if (a == 65) {5 revert();6 }7 }8}اسٹیٹ کی معلومات کا استعمال
ہر ایگزیکیوٹ ہونے والے پاتھ کی بلاک چین کی اپنی اسٹیٹ ہوتی ہے۔ ایک اسٹیٹ یا تو تیار ہوتی ہے یا اسے ختم کر دیا جاتا ہے، جس کا مطلب ہے کہ یہ ایک THROW یا REVERT ہدایت تک پہنچ جاتی ہے:
- m.ready_statesopens in a new tab: تیار اسٹیٹس کی فہرست (انہوں نے REVERT/INVALID ایگزیکیوٹ نہیں کیا)
- m.killed_statesopens in a new tab: ختم شدہ اسٹیٹس کی فہرست
- m.all_statesopens in a new tab: تمام اسٹیٹس
1for state in m.all_states:2 # do something with stateآپ اسٹیٹ کی معلومات تک رسائی حاصل کر سکتے ہیں۔ مثال کے طور پر:
state.platform.get_balance(account.address): اکاؤنٹ کا بیلنسstate.platform.transactions: ٹرانزیکشنز کی فہرستstate.platform.transactions[-1].return_data: آخری ٹرانزیکشن کے ذریعے واپس کیا گیا ڈیٹا
آخری ٹرانزیکشن کے ذریعے واپس کیا گیا ڈیٹا ایک ایرے ہے، جسے ABI.deserialize کے ساتھ ایک ویلیو میں تبدیل کیا جا سکتا ہے، مثال کے طور پر:
1data = state.platform.transactions[0].return_data2data = ABI.deserialize("uint", data)ٹیسٹ کیس کیسے تیار کریں
ٹیسٹ کیس تیار کرنے کے لیے m.generate_testcase(state, name)opens in a new tab کا استعمال کریں:
1m.generate_testcase(state, 'BugFound')خلاصہ
- آپ m.all_states کے ساتھ اسٹیٹ پر اعادہ کر سکتے ہیں
state.platform.get_balance(account.address)اکاؤنٹ کا بیلنس واپس کرتا ہےstate.platform.transactionsٹرانزیکشنز کی فہرست واپس کرتا ہےtransaction.return_dataواپس کیا گیا ڈیٹا ہےm.generate_testcase(state, name)اسٹیٹ کے لیے ان پٹس تیار کرتا ہے
خلاصہ: تھروئنگ پاتھ حاصل کرنا
1from manticore.ethereum import ManticoreEVM23m = ManticoreEVM()45with open('example.sol') as f:6 source_code = f.read()78user_account = m.create_account(balance=1000)9contract_account = m.solidity_create_contract(source_code, owner=user_account)1011symbolic_var = m.make_symbolic_value()12contract_account.f(symbolic_var)1314## Check if an execution ends with a REVERT or INVALID15for state in m.terminated_states:16 last_tx = state.platform.transactions[-1]17 if last_tx.result in ['REVERT', 'INVALID']:18 print('Throw found {}'.format(m.workspace))19 m.generate_testcase(state, 'ThrowFound')سب دکھائیںاوپر دیا گیا تمام کوڈ آپ example_run.pyopens in a new tab میں تلاش کر سکتے ہیں
نوٹ کریں کہ ہم ایک بہت آسان اسکرپٹ تیار کر سکتے تھے، کیونکہ terminated_state کے ذریعے واپس کی گئی تمام اسٹیٹس کے نتیجے میں REVERT یا INVALID ہوتا ہے: اس مثال کا مقصد صرف یہ دکھانا تھا کہ API میں ہیرا پھیری کیسے کی جائے۔
پابندیاں شامل کرنا
ہم دیکھیں گے کہ ایکسپلوریشن کو کیسے محدود کیا جائے۔ ہم یہ فرض کریں گے کہ f() کی
دستاویزات میں کہا گیا ہے کہ فنکشن کو کبھی بھی a == 65 کے ساتھ کال نہیں کیا جاتا، لہذا a == 65 والا کوئی بھی بگ حقیقی بگ نہیں ہے۔ ہدف اب بھی درج ذیل اسمارٹ کنٹریکٹ example.solopens in a new tab ہے:
1pragma solidity >=0.4.24 <0.6.0;2contract Simple {3 function f(uint a) payable public{4 if (a == 65) {5 revert();6 }7 }8}آپریٹرز
Operatorsopens in a new tab ماڈیول پابندیوں کی ہیرا پھیری میں سہولت فراہم کرتا ہے، دیگر چیزوں کے علاوہ یہ فراہم کرتا ہے:
- Operators.AND,
- Operators.OR,
- Operators.UGT (غیر دستخط شدہ سے بڑا),
- Operators.UGE (غیر دستخط شدہ سے بڑا یا برابر)،
- Operators.ULT (غیر دستخط شدہ سے کم)،
- Operators.ULE (غیر دستخط شدہ سے کم یا برابر)۔
ماڈیول کو امپورٹ کرنے کے لیے درج ذیل کا استعمال کریں:
1from manticore.core.smtlib import OperatorsOperators.CONCAT ایک ایرے کو ایک ویلیو سے جوڑنے کے لیے استعمال کیا جاتا ہے۔ مثال کے طور پر، ایک ٹرانزیکشن کے return_data کو ایک ویلیو میں تبدیل کرنے کی ضرورت ہے تاکہ اسے دوسری ویلیو کے خلاف چیک کیا جا سکے:
1last_return = Operators.CONCAT(256, *last_return)پابندیاں
آپ پابندیوں کا استعمال عالمی سطح پر یا کسی مخصوص اسٹیٹ کے لیے کر سکتے ہیں۔
عالمی پابندی
عالمی پابندی شامل کرنے کے لیے m.constrain(constraint) کا استعمال کریں۔
مثال کے طور پر، آپ ایک سمبولک ایڈریس سے ایک کنٹریکٹ کو کال کر سکتے ہیں، اور اس ایڈریس کو مخصوص ویلیوز تک محدود کر سکتے ہیں:
1symbolic_address = m.make_symbolic_value()2m.constraint(Operators.OR(symbolic == 0x41, symbolic_address == 0x42))3m.transaction(caller=user_account,4 address=contract_account,5 data=m.make_symbolic_buffer(320),6 value=0)اسٹیٹ کی پابندی
کسی مخصوص اسٹیٹ میں پابندی شامل کرنے کے لیے state.constrain(constraint)opens in a new tab کا استعمال کریں۔ اس کا استعمال اسٹیٹ کو اس کی ایکسپلوریشن کے بعد محدود کرنے کے لیے کیا جا سکتا ہے تاکہ اس پر کچھ خصوصیت کی جانچ کی جا سکے۔
پابندی کی جانچ کرنا
یہ جاننے کے لیے کہ کیا کوئی پابندی اب بھی قابل عمل ہے، solver.check(state.constraints) کا استعمال کریں۔
مثال کے طور پر، درج ذیل symbolic_value کو 65 سے مختلف ہونے پر مجبور کرے گا اور یہ جانچے گا کہ کیا اسٹیٹ اب بھی قابل عمل ہے:
1state.constrain(symbolic_var != 65)2if solver.check(state.constraints):3 # state is feasibleخلاصہ: پابندیاں شامل کرنا
پچھلے کوڈ میں پابندی شامل کرنے پر، ہم حاصل کرتے ہیں:
1from manticore.ethereum import ManticoreEVM2from manticore.core.smtlib.solver import Z3Solver34solver = Z3Solver.instance()56m = ManticoreEVM()78with open("example.sol") as f:9 source_code = f.read()1011user_account = m.create_account(balance=1000)12contract_account = m.solidity_create_contract(source_code, owner=user_account)1314symbolic_var = m.make_symbolic_value()15contract_account.f(symbolic_var)1617no_bug_found = True1819## Check if an execution ends with a REVERT or INVALID20for state in m.terminated_states:21 last_tx = state.platform.transactions[-1]22 if last_tx.result in ['REVERT', 'INVALID']:23 # we do not consider the path were a == 6524 condition = symbolic_var != 6525 if m.generate_testcase(state, name="BugFound", only_if=condition):26 print(f'Bug found, results are in {m.workspace}')27 no_bug_found = False2829if no_bug_found:30 print(f'No bug found')سب دکھائیںاوپر دیا گیا تمام کوڈ آپ example_run.pyopens in a new tab میں تلاش کر سکتے ہیں
صفحہ کی آخری تازہ کاری: 26 اپریل، 2024