เขียนรหัสที่สั้นที่สุดที่ทำให้เกิด Segmentation Fault (SIGSEGV)ในภาษาการเขียนโปรแกรมใด ๆ
เขียนรหัสที่สั้นที่สุดที่ทำให้เกิด Segmentation Fault (SIGSEGV)ในภาษาการเขียนโปรแกรมใด ๆ
คำตอบ:
main;
มันคือการประกาศตัวแปร - int
ประเภทมีนัย (คัดลอกคุณสมบัติจากภาษา B) และ0
เป็นค่าเริ่มต้น เมื่อดำเนินการนี้จะพยายามที่จะดำเนินการเป็นจำนวน (ตัวเลขไม่ได้ปฏิบัติการ) SIGSEGV
และสาเหตุ
0
ที่จริงมันเป็น static
ตัวแปรเริ่มต้นเป็น0
และmain;
เป็นstatic
ตามที่ฉันประกาศไว้นอกฟังก์ชั่น c-faq.com/decl/initval.html
main
int มันอยู่ใน.bss
โดยปกติแล้วฟังก์ชั่นจะอยู่ใน.text
เมื่อเคอร์เนลโหลดโปรแกรม elf มันสร้างหน้าปฏิบัติการสำหรับ.text
และไม่ - ใช้.bss
งานได้ดังนั้นเมื่อเรียก main คุณจะข้ามไปยังหน้าที่ไม่สามารถเรียกใช้ได้และการดำเนินการบางอย่างในหน้านั้นเป็นความผิด
main __attribute__((section(".text#")))=0xc3;
FTFY (อย่างน้อยก็ดูเหมือนว่าจะกลับมาโดยไม่ขัดข้องกับ x86 ของฉัน)
const main=195;
หรือสั้น ที่น่าสนใจคือมันใช้งานได้เป้าหมายของการแข่งขันกอล์ฟรหัสนี้คือการทำให้รหัส segfault ไม่ทำงาน :)
kill -11 $$
RET
รหัส segfaults นี้
exec'()'*7**6
Windows รายงานรหัสข้อผิดพลาดของ c00000fd (Stack Overflow) ซึ่งฉันคิดว่าเป็นประเภทย่อยของความผิดพลาดในการแบ่งกลุ่ม
ขอบคุณ Alex A. และ Mego จึงได้รับการยืนยันว่าทำให้เกิดข้อผิดพลาดในการแบ่งส่วนในระบบ Mac และ Linux เช่นกัน Python เป็นภาษาที่ใช้ในการหยุดโปรแกรมของคุณ
Segmentation fault: 11
บน Mac
Segmentation fault (core dumped)
บน Linux
\def~#1{\meaning}\write0{\expandafter~\string}\bye
นี่อาจเป็นจุดบกพร่องแต่ไม่มีใน TeX ดั้งเดิมที่เขียนโดย Knuth: การคอมไพล์โค้ดด้วยtex filename.tex
แทนที่จะpdftex filename.tex
ไม่สร้าง segfault
>>> import ctypes;ctypes.string_at(0)
Segmentation fault
ที่มา: http://bugs.python.org/issue1215#msg143236
>>> import sys;sys.setrecursionlimit(1<<30);f=lambda f:f(f);f(f)
Segmentation fault
ที่มา: http://svn.python.org/view/python/trunk/Lib/test/crashers/recursive_call.py?view=markup
นี่เป็นเวอร์ชั่น Python ที่ฉันกำลังทดสอบ:
Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
โดยทั่วไปแล้ว Python interpreter นั้นยากที่จะผิดพลาด แต่ข้างต้นนั้นเป็นการเลือกที่ผิด ...
main(){raise(11);}
int func()
ทำได้โดยไม่ต้องประกาศที่มองเห็นเรียบเรียงโดยปริยายบอกว่ามันเป็น เช่นฟังก์ชันที่ส่งคืนint
โดยรับพารามิเตอร์ที่ไม่ระบุ ในกรณีนี้raise
คือฟังก์ชันที่ส่งคืนค่า int รับอาร์กิวเมนต์ int ดังนั้นจึงสามารถใช้งานได้ (แม้ว่าคอมไพเลอร์จะบ่น)
/(?{??})/
ใน 5.14 เอ็นจิ้น regex นั้นถูกสร้างขึ้นมาใหม่เพื่อที่จะไม่สามารถชนได้ด้วยวิธีนี้ แต่ 5.12 และก่อนหน้านี้จะเป็น segfault ถ้าคุณลองทำสิ่งนี้
สิ่งนี้จะดูแปลก แต่ในระบบ Windows แบบ 32 บิตการสร้างและดำเนินการไฟล์. com ว่างอาจทำให้เกิด segfault ขึ้นอยู่กับ ... บางสิ่งบางอย่าง DOS เพิ่งยอมรับ (8086 ที่ไม่มีการจัดการหน่วยความจำไม่มีเซ็กเมนต์ที่มีความหมายต่อความผิดพลาด) และ Windows 64 บิตปฏิเสธที่จะเรียกใช้ (x86-64 ไม่มีโหมด v86 ในการเรียกใช้ไฟล์. com)
<.
ใช่นี้ขึ้นอยู่กับการใช้งาน SIGSEGV เป็นผลมาจากคอมไพเลอร์ที่ดี
<
ควรจะไม่มีผลกระทบหรือล้อมรอบ
foreign import ccall main::IO()
สิ่งนี้จะสร้าง segfault เมื่อรวบรวมกับ GHC และเรียกใช้ ไม่จำเป็นต้องตั้งค่าสถานะส่วนขยายเนื่องจากอินเตอร์เฟสของฟังก์ชันต่างประเทศอยู่ในมาตรฐาน Haskell 2010
รุ่น C คือ:
*(int*)0=0;
โปรแกรมทั้งหมด (ไม่ตรงตามมาตรฐาน ISO สมมุติว่า K&R C) มีความยาว 19 ตัวอักษร:
main(){*(int*)0=0;}
แอสเซมเบลอร์ตัวแปร:
orl $0,0
โปรแกรมทั้งหมดยาว 24 ตัวอักษร (เพียงเพื่อการประเมินผลเนื่องจากไม่ใช่แอสเซมเบลอร์จริง ๆ ):
main(){asm("orl $0,0");}
แก้ไข :
คู่สายพันธุ์ C อันแรกใช้ zero-initialization ตัวแปรโกลบอลพอยน์เตอร์:
*p;main(){*p=0;}
อันที่สองใช้การเรียกซ้ำแบบไม่สิ้นสุด:
main(){main();}
ตัวแปรสุดท้ายคืออักขระที่สั้นที่สุดหนึ่ง - 7 (15) ตัว
แก้ไข 2 :
คิดค้นตัวแปรอีกตัวหนึ่งซึ่งสั้นกว่าตัวแปรใด ๆ ข้างต้น - 6 (14) ตัวอักษร มันจะถือว่าสตริงตัวอักษรถูกใส่ลงในเซ็กเมนต์แบบอ่านอย่างเดียว
main(){*""=0;}
แก้ไข 3 :
และความพยายามครั้งสุดท้ายของฉัน - ความยาว 1 ตัวอักษร:
P
เพียงแค่รวบรวมมันเช่นนั้น:
cc -o segv -DP="main(){main();}" segv.c
main
คือตัวแปรโกลบอลโกลบอลที่กำหนดค่าเริ่มต้นเป็นศูนย์ดังนั้นสิ่งที่เราได้รับคือผลลัพธ์ของการพยายามดำเนินการศูนย์ไบต์บางส่วน ใน x86 มันจะเป็นสิ่งที่ต้องการซึ่งเป็นคำแนะนำที่ถูกต้องสมบูรณ์ซึ่งพยายามที่จะเข้าถึงหน่วยความจำที่อยู่ที่เก็บไว้ในadd %al,(%rax)
%rax
โอกาสของการมีที่อยู่ที่ดีมีเพียงเล็กน้อย
[dx0]dx
ทำให้เกิดการล้นสแต็ค
[dx0]
เก็บdx0
ในสแต็กจากนั้นd
ทำซ้ำองค์ประกอบสแต็คด้านบนจากนั้นx
จะปรากฏองค์ประกอบสแต็คด้านบน ( dx0
) และดำเนินการ ซึ่งทำซ้ำองค์ประกอบสแต็คด้านบนและเริ่มดำเนินการ ... 0
ความจำเป็นที่จะต้องมีเพื่อป้องกันไม่ให้นี่เป็นการเรียกแบบหางดังนั้นพวกมันจึงสร้างขึ้นทั้งหมด
ทางออกที่โกงเล็กน้อยคือการโกนเคล็ดลับทุบตีของ Joey Adams :
kill 11,$$
อย่างไรก็ตามเพื่อให้ได้ segfault ที่แท้จริงใน Perl unpack p
เป็นทางออกที่ชัดเจน
unpack p,1x8
ในทางเทคนิคสิ่งนี้ไม่ได้รับประกันว่าจะได้รับ segfault เนื่องจากที่อยู่ 0x31313131 (หรือ 0x313131313131313131 บนระบบ 64 บิต) อาจชี้ไปยังพื้นที่ที่อยู่ที่ถูกต้องโดยบังเอิญ แต่ราคาถูกกว่านั้น นอกจากนี้ถ้า perl ถูกพอร์ตไปยังแพลตฟอร์มที่พอยน์เตอร์ยาวกว่า 64 บิตx8
จะต้องเพิ่มขึ้น
1x8
อะไร
"11111111".
import os
os.kill(os.getpid(),11)
กำลังส่งสัญญาณ 11 (SIGSEGV) ในไพ ธ อน
from os import*
และkill(getpid(),11)
Obj.magic 0 0
สิ่งนี้ใช้ฟังก์ชั่นObj.magic
ซึ่งเป็นการข่มขู่ชนิดสองอย่างไม่ปลอดภัย ในกรณีนี้มันจะรวมเป็น 0 (จัดเก็บเป็นค่าทันที 1 เนื่องจากบิตแท็กที่ใช้โดย GC) กับประเภทฟังก์ชั่น (เก็บไว้เป็นตัวชี้) ดังนั้นจึงพยายามปฏิเสธที่อยู่ 1 และแน่นอนว่าจะแยกจากกัน
it coerces 0 (stored as the immediate value 1)
- ทำไมถึงถูกจัดเก็บเป็น 1
Obj.magic()0
เป็นหนึ่ง :) ถ่านสั้น
แข็งแรงเล่นกอล์ฟ
. $0
รวมสคริปต์ซ้ำเข้าไปในตัวเอง
อธิบาย
การดำเนินการ "ซอร์ส" (.) แบบเรียกซ้ำทำให้เกิดการล้นสแต็กในที่สุดและเนื่องจากBashไม่ได้รวมเข้ากับlibsigsegvผลลัพธ์นี้จึงเป็น SIGSEGV
โปรดทราบว่านี้ไม่ได้เป็นข้อผิดพลาด แต่พฤติกรรมที่คาดหวังตามที่กล่าวไว้ที่นี่
ทดสอบ
./bang
Segmentation fault (core dumped)
⌠[]+⌡9!*.
หากข้างต้นไม่ผิดพลาดให้ลองเพิ่มจำนวน (ระบุตัวเลขหลายหลักในจริงด้วยเครื่องหมายโคลอน)
ขัดข้องล่ามโดยใช้ประโยชน์จากบั๊กในงูหลามที่เกี่ยวข้องกับitertools.chain
วัตถุที่ซ้อนกันอย่างล้ำลึกซึ่งใช้ในการปฏิบัติงาน+
จริง
System.Runtime.InteropServices.Marshal.ReadInt32(IntPtr.Zero);
unsafe{int i=*(int*)0;}
ต้องรวบรวมด้วย / ไม่ปลอดภัยเพื่อให้การทำงานนี้ ด้วยเหตุผลบางอย่างที่ฉันไม่เข้าใจ*(int*)0=0
เพียงแค่โยน NullReferenceException ในขณะที่รุ่นนี้ให้การละเมิดการเข้าถึงที่เหมาะสม
int i=*(int*)0;
ผลตอบแทน NullReferenceException สำหรับฉัน
*(int*)-1=0
และรับการละเมิดการเข้าถึง
*(int*)0=0
เกิดข้อยกเว้นเกิดขึ้นเนื่องจากการปรับให้เหมาะสม โดยเฉพาะอย่างยิ่งที่จะหลีกเลี่ยงค่าใช้จ่ายในการตรวจสอบเพื่อnull
เพิ่มประสิทธิภาพการตรวจสอบอาจลบ null แต่เมื่อ segfault เกิดขึ้นมันอาจ rethrow NullReferenceException
ว่ามันเป็นที่เหมาะสม
$ pil
: ('0)
Segmentation fault
นี่คือพฤติกรรมที่ตั้งใจไว้ ตามที่อธิบายไว้ในเว็บไซต์:
หากภาษาโปรแกรมบางโปรแกรมอ้างว่าเป็น "Swiss Army Knife of Programming" ดังนั้น PicoLisp อาจถูกเรียกว่า "Scalpel of Programming": คมชัดแม่นยำขนาดเล็กและเบา แต่ก็มีอันตรายในมือของผู้ไม่มีประสบการณ์
real,pointer::p(:)=>null()
p(1)=0.
end
รวบรวม:
gfortran segv.f90 -o segv
การดำเนินการ:
./segv
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0x7FF85FCAE777
#1 0x7FF85FCAED7E
#2 0x7FF85F906D3F
#3 0x40068F in MAIN__ at segv.f90:?
Erreur de segmentation (core dumped)
วัสดุ:
gfortran --version
GNU Fortran (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
main(a){*(&a-1)=1;}
มันคุ้มค่าที่อยู่ corrupts การกลับมาของฟังก์ชั่นหลักจึงได้รับ SIGSEGV main
ในการกลับมาของ
memf 1
memf
หมายถึงหน่วยความจำว่าง1
ถูกตีความว่าเป็นตัวชี้
สิ่งนี้มักจะมีประโยชน์สำหรับการแก้ไขจุดบกพร่อง
a=(<int*>0)[0]
(สิ่งนี้กำลังกลายเป็นธีมของฉันอาจเป็นเพราะเป็นภาษาเดียวที่ฉันรู้ว่าไม่มีใครอยู่ที่นี่)
inc(r0)
เพิ่มไบต์เดียวที่จ่าหน้าโดยค่าเริ่มต้นของ r0 [ซึ่งเกิดขึ้นเป็น 05162 ตาม simh debugger] เมื่อเริ่มต้นโปรแกรม
0000000 000407 000002 000000 000000 000000 000000 000000 000000
0000020 005210 000000
และเช่นเคยไบต์ภายนอกที่อยู่ด้านท้ายสามารถลบออกด้วยแถบ
ฉันพยายามทำให้แหล่งที่มาสั้นลง แต่ได้รับข้อผิดพลาดทางไวยากรณ์หรือ SIGBUS เสมอ
ในการตอบสนองต่อคำถามของฉัน Amro ก็คิดเรื่องนี้ขึ้นมา
S = struct();
S = setfield(S, {}, 'g', {}, 0)
clear()
ล้างทุกอย่างไม่เพียง แต่ขอบเขตปัจจุบันซึ่งทำให้บอร์กจำนวนมากซึ่งส่งผลให้ JS เกิดระเบิดและแยกกันไม่ออก
j1Z
นี้จะเป็นส่วนหนึ่งที่ผมอธิบายวิธีการที่ฉันมากับคำตอบนี้นอกจากฉันถูกต้องตามกฎหมายมีเงื่อนงำ หากใครสามารถอธิบายสิ่งนี้ให้ฉันฉันจะขอบคุณ
คำอธิบาย
j
ยกกำลังสองฐานและเรียกตัวเองซ้ำ ๆ จนกว่าฐานจะใหญ่อย่างน้อยเท่ากับจำนวน เนื่องจากฐานเป็น0นั่นไม่เคยเกิดขึ้น ด้วยการ จำกัด การเรียกซ้ำที่สูงพอคุณจะได้รับ segfault
j
เกี่ยวกับการ1
และ0
ซึ่งพยายามที่จะแปลงเป็นฐาน1
0
ทำไม segfaults นั้นฉันไม่มีความคิด ...
j
ยกกำลังสองฐานและเรียกตัวเองซ้ำ ๆ จนกว่าฐานจะใหญ่อย่างน้อยเท่ากับจำนวน เนื่องจากฐานเป็น0นั่นไม่เคยเกิดขึ้น ด้วยการ จำกัด การเรียกซ้ำที่สูงพอคุณจะได้รับ segfault