Background
We already have a challenge about throwing SIGSEGV, so why not a challenge about throwing SIGILL?
What is SIGILL?
SIGILL is the signal for an illegal instruction at the processor, which happens very rarely. The default action after receiving SIGILL is terminating the program and writing a core dump. The signal ID of SIGILL is 4. You encounter SIGILL very rarely, and I have absolutely no idea how to generate it in your code except via sudo kill -s 4 <pid>.
Rules
You will have root in your programs, but if you don't want to for any reasons, you may also use a normal user. I'm on a Linux computer with German locale and I do not know the English text which is displayed after catching SIGILL, but I think it's something like 'Illegal instruction'. The shortest program which throws SIGILL wins.
27 Answers 27
PDP-11 Assembler (UNIX Sixth Edition), 1 byte
9
Instruction 9 is not a valid instruction on the PDP-11 (in octal, it would be 000011, which does not appear on the list of instructions (PDF)). The PDP-11 assembler that ships with UNIX Sixth Edition apparently echoes everything it doesn't understand into the file directly; in this case, 9 is a number, so it generates a literal instruction 9. It also has the odd property (unusual in assembly languages nowadays) that files start running from the start, so we don't need any declarations to make the program work.
You can test out the program using this emulator, although you'll have to fight with it somewhat to input the program.
Here's how things end up once you've figured out how to use the filesystem, the editor, the terminal, and similar things that you thought you already knew how to use:
% a.out
Illegal instruction -- Core dumped
I've confirmed with the documentation that this is a genuine SIGILL signal (and it even had the same signal number, 4, all the way back then!)
-
1\$\begingroup\$ It had the same signal number because POSIX and UNIX and the SUS are closely related :) \$\endgroup\$cat– cat2016年11月20日 13:57:04 +00:00Commented Nov 20, 2016 at 13:57
-
6\$\begingroup\$ Almost all of the signal numbers in V6 still have the same meanings today; the mnemonics have actually been less stable than the numbers. Compare minnie.tuhs.org/cgi-bin/utree.pl?file=V6/usr/sys/param.h with github.com/freebsd/freebsd/blob/master/sys/sys/signal.h — identical semantics for 1 through 13, but only 1, 2, and 13 have exactly the same names. (SIGALRM/14 and SIGTERM/15 were only added in V7.) (The System V lineage has a couple of changes, notably moving SIGBUS from 10 to 7 (replacing the useless SIGEMT) and SIGSYS above 15, to make room for SIGUSR1 and SIGUSR2.) \$\endgroup\$zwol– zwol2016年11月20日 19:35:44 +00:00Commented Nov 20, 2016 at 19:35
-
4\$\begingroup\$ @cat POSIX and SUS don't actually specify the values of signals - they do specify the meaning of some numbers when passed as arguments to the kill command, but SIGILL is not included. \$\endgroup\$Random832– Random8322016年11月20日 23:16:57 +00:00Commented Nov 20, 2016 at 23:16
-
10\$\begingroup\$
a.outhas multiple bytes in it, indeed (the9instruction compiles to two bytes, and the assembler also adds a header and footer to make the program executable). That's why I wrote the program in assembly language, not in machine code. The assembly language program has only one byte in, and compiles to a program with more bytes in; this is a code-golf problem (minimize the size of the source), not a sizecoding problem (minimize the size of the executable), so it's the 1-byte size of the source that matters. \$\endgroup\$user62131– user621312016年11月23日 02:39:34 +00:00Commented Nov 23, 2016 at 2:39 -
2\$\begingroup\$ Very clever abuse of an old but awesome system. \$\endgroup\$Mast– Mast2016年11月23日 11:45:45 +00:00Commented Nov 23, 2016 at 11:45
C (x86_64, tcc), 7 bytes
main=6;
Inspired by this answer.
How it works
The generated assembly looks like this.
.globl main
main:
.long 6
Note that TCC doesn't place the defined "function" in a data segment.
After compilation, _start will point to main as usual. When the resulting program is executed, it expects code in main and finds the little-endian(!) 32-bit integer 6, which is encoded as 0x06 0x00 0x00 0x00. The first byte – 0x06 – is an invalid opcode, so the program terminates with SIGILL.
C (x86_64, gcc), 13 bytes
const main=6;
How it works
Without the const modifier, the generated assembly looks like this.
.globl main
.data
main:
.long 6
.section .note.GNU-stack,"",@progbits
GCC's linker treats the last line as a hint that the generated object does not require an executable stack. Since main is explicitly placed in a data section, the opcode it contains isn't executable, so the program terminates will SIGSEGV (segmentation fault).
Removing either the second or the last line will make the generated executable work as intended. The last line could be ignored with the compiler flag -zexecstack (Try it online!), but this costs 12 bytes.
A shorter alternative is to declare main with the const modifier, resulting in the following assembly.
.globl main
.section .rodata
main:
.long 6
.section .note.GNU-stack,"",@progbits
This works without any compiler flags. Note that main=6; would write the defined "function" in data, but the const modifier makes GCC write it in rodata instead, which (at least on my platform) is allowed to contain code.
-
1\$\begingroup\$ Love the complete avoidance of even using a function :) How does this work in C terms, though? Does the compiler see that
mainis a 6 and try to call it (which I guess would make it give up and try the instruction)? \$\endgroup\$Mia yun Ruse– Mia yun Ruse2016年11月20日 16:15:01 +00:00Commented Nov 20, 2016 at 16:15 -
15\$\begingroup\$ @JackDobson it's undefined behavior, so it doesn't work in terms of C; you're at the compiler's mercy. Clang even has a warning for this for some reason: "variable named 'main' with external linkage has undefined behavior". \$\endgroup\$Bobby Sacamano– Bobby Sacamano2016年11月20日 16:32:22 +00:00Commented Nov 20, 2016 at 16:32
-
3\$\begingroup\$ GCC will complain about
mainnot being a function but only if you turn on the warnings (either-Wallor-pedanticwill do it). \$\endgroup\$zwol– zwol2016年11月20日 19:40:51 +00:00Commented Nov 20, 2016 at 19:40 -
4\$\begingroup\$ Also note that
06is only an invalid instruction in x86-64. In 32-bit mode, it'sPUSH ES, so this answer only works with compilers that default to-m64. See ref.x86asm.net/coder.html#x06. The only byte sequence that's guaranteed to decode as an illegal instruction on all future x86 CPUs is the 2 byte UD2:0F 0B. Anything else could be some future prefix or instruction-encoding. Still, upvoted for a cool way to get a C compiler to stick amainlabel on some bytes! \$\endgroup\$Peter Cordes– Peter Cordes2016年11月21日 04:35:47 +00:00Commented Nov 21, 2016 at 4:35 -
1\$\begingroup\$ Huh, that's weird that
-z execstackalso controls the.datasection. I checked with x86-64 gcc7.1.1 on Arch Linux, and you're right that that@progbitsdirective makes the data section non-executable, and that-z execstackoverrides it, and that the default (with no directive and no option) is an executable.datasection. I guessexecstackis more like executability for non-textsegments in general. \$\endgroup\$Peter Cordes– Peter Cordes2017年12月26日 05:25:19 +00:00Commented Dec 26, 2017 at 5:25
Swift, 5 bytes
[][0]
Access index 0 of an empty array. This calls fatalError(), which prints an error message and crashes with a SIGILL. You can try it here.
-
\$\begingroup\$ This is one of the trickier ones ;) \$\endgroup\$univalence– univalence2016年11月22日 18:22:28 +00:00Commented Nov 22, 2016 at 18:22
-
35\$\begingroup\$ ...why on earth does it crash with a SIGILL? Who thought that was an appropriate signal? Bloody hipsters :D \$\endgroup\$Muzer– Muzer2016年11月23日 14:01:40 +00:00Commented Nov 23, 2016 at 14:01
-
9\$\begingroup\$ @Asu No;
fatalError()intentionally crashes by runningud2. Why they chose to do that I do not know, but maybe they thought the error message "Illegal instruction" made sense because the program did something illegal. \$\endgroup\$NobodyNada– NobodyNada2016年11月23日 18:15:17 +00:00Commented Nov 23, 2016 at 18:15 -
2\$\begingroup\$ Brilliant. I would bet this is also the shortest Swift code to cause a crash. \$\endgroup\$JAL– JAL2016年11月23日 18:19:30 +00:00Commented Nov 23, 2016 at 18:19
-
3\$\begingroup\$ @JAL Yeah; I can't think of anything shorter. I tried
nil!, but the compiler couldn't infer the result type. (Also, hi JAL!) \$\endgroup\$NobodyNada– NobodyNada2016年11月23日 18:22:18 +00:00Commented Nov 23, 2016 at 18:22
GNU C, 25 bytes
main(){__builtin_trap();}
GNU C (a specific dialect of C with extensions) contains an instruction to crash the program intentionally. The exact implementation varies from version to version, but often the developers make an attempt to implement the crash as cheaply as possible, which normally involves the use of an illegal instruction.
The specific version I used to test is gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0; however, this program causes a SIGILL on a fairly wide range of platfoms, and thus is fairly portable. Additionally, it does it via actually executing an illegal instruction. Here's the assembly code that the above compiles into with default optimization settings:
main:
pushq %rbp
movq %rsp, %rbp
ud2
ud2 is an instruction that Intel guarantees will always remain undefined.
-
13\$\begingroup\$ −6:
main(){asm("ud2");}\$\endgroup\$wchargin– wchargin2016年11月20日 16:06:44 +00:00Commented Nov 20, 2016 at 16:06 -
\$\begingroup\$ Also, I don't know how we count bytes for raw assembly, but
00 00 0f 0bis the machine language forud2... \$\endgroup\$wchargin– wchargin2016年11月20日 16:08:53 +00:00Commented Nov 20, 2016 at 16:08 -
6\$\begingroup\$ @wchargin: that's an x86 + GNU C answer. This one is portable to all GNU systems. Also note that UD2 is only 2 bytes. IDK where you got those
00bytes; they're not part of the machine code for UD2. BTW, as I commented on Dennis's answer, there are one-byte illegal instructions in x86-64 for now, but they're not guaranteed to stay that way. \$\endgroup\$Peter Cordes– Peter Cordes2016年11月21日 04:43:09 +00:00Commented Nov 21, 2016 at 4:43 -
\$\begingroup\$ @wchargin: We count bytes for machine-code functions / programs like you'd expect. See some of my answers, like Adler32 in 32 bytes of x86-64 machine code, or GCD in 8 bytes of x86-32 machine code. \$\endgroup\$Peter Cordes– Peter Cordes2016年11月21日 04:44:10 +00:00Commented Nov 21, 2016 at 4:44
-
2\$\begingroup\$ @Ruslan: They aren't;
00 00decodes the same in x86-64 (asadd [rax], al).00 00 0f 0bwould usually SIGSEGV before SIGILL, unless you happened to have a writeable pointer inrax. \$\endgroup\$Peter Cordes– Peter Cordes2016年11月24日 09:17:27 +00:00Commented Nov 24, 2016 at 9:17
C (x86_64), 11, 30, 34, or 34+15 = 49 bytes
main[]="/";
c=6;main(){((void(*)())&c)();}
main(){int c=6;((void(*)())&c)();}
I've submitted a couple of solutions that use library functions to throw SIGILL via various means, but arguably that's cheating, in that the library function solves the problem. Here's a range of solutions that use no library functions, and make varying assumptions about where the operating system is willing to let you execute non-executable code. (The constants here are chosen for x86_64, but you could change them to get working solutions for most other processors that have illegal instructions.)
06 is the lowest-numbered byte of machine code that does not correspond to a defined instruction on an x86_64 processor. So all we have to do is execute it. (Alternatively, 2F is also undefined, and corresponds to a single printable ASCII character.) Neither of these are guaranteed to always be undefined, but they aren't defined as of today.
The first program here executes 2F from the read-only data segment. Most linkers aren't capable of producing a working jump from .text to .rodata (or their OS's equivalent) as it's not something that would ever be useful in a correctly segmented program; I haven't found an operating system on which this works yet. You'd also have to allow for the fact that many compilers want the string in question to be a wide string, which would require an additional L; I'm assuming that any operating system that this works on has a fairly outdated view of things, and thus is building for a pre-C94 standard by default. It's possible that there's nowhere this program works, but it's also possible that there's somewhere this program works, and thus I'm listing it in this collection of more-dubious-to-less-dubious potential answers. (After I posted this answer, Dennis also mentioned the possibility main[]={6} in chat, which is the same length, and which doesn't run into problems with character width, and even hinted at the potential for main=6; I can't reasonably claim these answers as mine, as I didn't think of them myself.)
The second program here executes 06 from the read-write data segment. On most operating systems this will cause a segmentation fault, because writable data segments are considered to be a bad design flaw that makes exploits likely. This hasn't always been the case, though, so it probably works on a sufficiently old version of Linux, but I can't easily test it.
The third program executes 06 from the stack. Again, this causes a segmentation fault nowadays, because the stack is normally classified as nonwritable for security reasons. The linker documentation I've seen heavily implies that it used to be legal to execute from the stack (unlike the preceding two cases, doing so is occasionally useful), so although I can't test it, I'm pretty sure there's some version of Linux (and probably other operating systems) on which this works.
Finally, if you give -Wl,-z,execstack (15 byte penalty) to gcc (if using GNU ld as part of the backend), it will explicitly turn off executable stack protection, allowing the third program to work and give an illegal operation signal as expected. I have tested and verified this 49-byte version to work. (Dennis mentions in chat that this option apparently works with main=6, which would give a score of 6+15. I'm pretty surprised that this works, given that the 6 blatantly isn't on the stack; the link option apparently does more than its name suggests.)
-
1\$\begingroup\$ On x86-64/linux with gcc6 in its default (lenient) mode,
const main=6;works, as do several variations. This linker (which I suspect is also your linker) is capable of generating a jump from.textto.rodata; the problem you were having is that, withoutconst, you're jumping into the writable data segment (.data), which is not executable on modern hardware. It would have worked on older x86, where the memory protection hardware could not mark pages as readable-but-not-executable. \$\endgroup\$zwol– zwol2016年11月20日 16:19:16 +00:00Commented Nov 20, 2016 at 16:19 -
\$\begingroup\$ Note that even in C89,
mainis required to be a function (§5.1.2.2.1) -- I don't know why gcc considers declaringmainas a data object to only deserve a warning, and only with-pedanticon the command line. Someone back in the early 1990s perhaps thought that nobody would do that by accident, but it's not like it's a useful thing to do on purpose except for this sort of game. \$\endgroup\$zwol– zwol2016年11月20日 16:25:44 +00:00Commented Nov 20, 2016 at 16:25 -
2\$\begingroup\$ ... Rereading again, it seems you expected
main[]="/"to jump to the read-only data segment, because string literals go in rodata. You've been caught out by the difference betweenchar *foo = "..."andchar foo[] = "...".char *foo = "..."is syntactic sugar forconst char __inaccessible1[] = "..."; char *foo = (char *)&__inaccessible1[0];, so the string literal does go in rodata, andfoois a separate, writable global variable that points to it. Withchar foo[] = "...", however, the entire array goes in the writable data segment. \$\endgroup\$zwol– zwol2016年11月20日 17:07:40 +00:00Commented Nov 20, 2016 at 17:07
GNU as (x86_64), 3 bytes
ud2
$ xxd sigill.S
00000000: 7564 32 ud2
$ as --64 sigill.S -o sigill.o ; ld -S sigill.o -o sigill
sigill.S: Assembler messages:
sigill.S: Warning: end of file not at end of a line; newline inserted
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400078
$ ./sigill
Illegal instruction
$ objdump -d sigill
sigill: file format elf64-x86-64
Disassembly of section .text:
0000000000400078 <__bss_start-0x200002>:>
400078: 0f 0b ud2
-
\$\begingroup\$ There must be a way to express that in a two-byte "source"... \$\endgroup\$OrangeDog– OrangeDog2016年11月21日 17:16:39 +00:00Commented Nov 21, 2016 at 17:16
-
\$\begingroup\$ Oh, clever. I was wondering if there was a way to build this which would put the entry point at the start of the file (with no declarations) and which wouldn't incur penalties for an unusual build system configuration. I couldn't find one, but it looks like you did. \$\endgroup\$user62131– user621312016年11月22日 00:57:44 +00:00Commented Nov 22, 2016 at 0:57
-
\$\begingroup\$ @ais523: yeah, my usual NASM / YASM build-script (
asm-link) for single-file toy programs would build an executable from this source the same way, sincelddefaults the entry point to the start of the text segment or something like that. I just didn't think of going for asm source size on this one :P \$\endgroup\$Peter Cordes– Peter Cordes2016年11月24日 09:21:16 +00:00Commented Nov 24, 2016 at 9:21
Bash on Raspbian on QEMU, 4 (1?) bytes
Not my work. I merely report the work of another. I'm not even in a position to test the claim. Since a crucial part of this challenge seems to be finding an environment where this signal will be raised and caught, I'm not including the size of QEMU, Raspbian, or bash.
On Feb 27, 2013 8:49 pm, user emlhalac reported "Getting 'illegal instruction' when trying to chroot" on the Raspberry Pi fora.
ping
producing
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal instruction (core dumped)
I imagine much shorter commands will produce this output, for instance, tr.
EDIT: Based on @fluffy's comment, reduced the conjectured lower bound on input length to "1?".
-
7\$\begingroup\$ I'd think the
[command would win. :) \$\endgroup\$fluffy– fluffy2016年11月21日 22:40:37 +00:00Commented Nov 21, 2016 at 22:40
x86 MS-DOS COM file, 2 bytes
EDIT: As pointed out in the comments, DOS itself will not trap the CPU exception and will simply hang (not just the app, the entire OS). Running on a 32-bit NT-based OS such as Windows XP will, indeed, trigger an illegal instruction signal.
0F 0B
From the documentation:
Generates an invalid opcode. This instruction is provided for software testing to explicitly generate an invalid opcode.
Which is pretty self-explanatory. Save as a .com file, and (削除) run in any DOS emulator (削除ここまで) DOS emulators will just crash. Run on Windows XP, Vista, or 7 32-bit.
-
1\$\begingroup\$ It technically does cause the processor to generate an illegal instruction exception. However, DOS has very limited memory protection and exception handling capabilities, and I wouldn't be surprised if it just lead to undefined behavior / OS crash. The OP didn't say the kernel had to catch the error and print "Illegal Instruction" to the console. \$\endgroup\$maservant– maservant2016年11月20日 20:45:17 +00:00Commented Nov 20, 2016 at 20:45
-
4\$\begingroup\$ I thought of this solution, but I don't believe it's valid. The question requires an illegal instruction signal, not just an illegal instruction processor trap, so the aim was to find an operating system which would actually generate a signal in response to the
#UDtrap. (Also, I decided to actually test it, and it appeared to throw my DOS emulator into an infinite loop.) \$\endgroup\$user62131– user621312016年11月20日 22:14:19 +00:00Commented Nov 20, 2016 at 22:14 -
2\$\begingroup\$ I tested this on actual MS-DOS on an AMD K6-II. Running it just hangs the system, both with and without EMM386 running. (EMM386 traps some errors and halts the system with a message, so it was worth testing to see if it made a difference.) \$\endgroup\$Mark– Mark2016年11月21日 01:43:40 +00:00Commented Nov 21, 2016 at 1:43
-
2\$\begingroup\$ Yes, DOS-based windows should be able to really catch the trap and at least crash the app. \$\endgroup\$asu– asu2016年11月23日 18:05:15 +00:00Commented Nov 23, 2016 at 18:05
-
2\$\begingroup\$ @Asu I can confirm that this works on XP 32-bit, and will probably work on all other 32-bit Windows systems. I agree that this isn't a solution on DOS itself, as it just crashes. \$\endgroup\$maservant– maservant2016年11月23日 22:00:18 +00:00Commented Nov 23, 2016 at 22:00
C (32-bit Windows), 34 bytes
f(i){(&i)[-1]-=9;}main(){f(2831);}
This only works if compiling without optimizations (else, the illegal code in the f function is "optimized out").
Disassembly of the main function looks like this:
68 0f 0b 00 00 push 0b0f
e8 a1 d3 ff ff call _f
...
We can see that it uses a push instruction with a literal value 0b0f (little-endian, so its bytes are swapped). The call instruction pushes a return address (of the ... instruction), which is situated on the stack near the parameter of the function. By using a [-1] displacement, the function overrides the return address so it points 9 bytes earlier, where the bytes 0f 0b are.
These bytes cause an "undefined instruction" exception, as designed.
Java, (削除) 50 (削除ここまで) (削除) 43 (削除ここまで) 24 bytes
a->a.exec("kill -4 $$");
This is a java.util.function.Consumer<Runtime>1 whose command is stolen from fluffy's answer. It works because you must call it as whateverNameYouGiveIt.accept(Runtime.getRuntime())!
Note that this will create a new process and make it throw a SIGILL rather than throwing a SIGILL itself.
1 - Technically, it can also be a java.util.function.Function<Runtime, Process> because Runtime#exec(String) returns a java.lang.Process which can be used to control the process you just created by executing a shell command.
For the sake of doing something more impressive in such a verbose language, here's a (削除) 72 (削除ここまで) (削除) 60 (削除ここまで) 48-byte bonus:
a->for(int b=0;;b++)a.exec("sudo kill -s 4 "+b);
This one is another Consumer<Runtime> that goes through ALL processes (including itself), making each of them throw a SIGILL. Better brace for a violent crash.
And another bonus (a Consumer<ANYTHING_GOES>), which at least pretends to throw a SIGILL in 20 bytes:
a->System.exit(132);
Perl, 9 bytes
kill+4,$$
Simply calls the appropriate library function for signalling a process, and gets the program to signal itself with SIGILL. No actual illegal instructions are involved here, but it produces the appropriate result. (I think this makes the challenge fairly cheap, but if anything's allowed, this is the loophole you'd use...)
-
1\$\begingroup\$ Came here to post the same, with a space instead of the
+. :) \$\endgroup\$simbabque– simbabque2016年11月21日 13:16:45 +00:00Commented Nov 21, 2016 at 13:16 -
2\$\begingroup\$ When people learn Perl for non-golf programming, they learn it with a
+. After golfing for a while, they do+occasionally to show off. Eventually, they've written enough programs where they needed to avoid whitespace for some reason or other that the+becomes habit. (It also parses less ambiguously, because it works around triggering the special case in the parser for parentheses.) \$\endgroup\$user62131– user621312016年11月21日 13:33:34 +00:00Commented Nov 21, 2016 at 13:33 -
\$\begingroup\$ Using the "0" pid option from another example we can apparently shave off another byte.
perl -E'kill+4,0'\$\endgroup\$Ashley– Ashley2022年06月30日 20:33:39 +00:00Commented Jun 30, 2022 at 20:33
ARM Unified Assembler Language (UAL), 3 bytes
nop
For example:
$ as ill.s -o ill.o
$ ld ill.o -o ill
ld: warning: cannot find entry symbol _start; defaulting to 00010054
$ ./ill
Illegal instruction
After executing nop, the processor interprets the .ARM.attributes section as code and encounters an illegal instruction somewhere there:
$ objdump -D ill
ill: file format elf32-littlearm
Disassembly of section .text:
00010054 <__bss_end__-0x10004>:
10054: e1a00000 nop ; (mov r0, r0)
Disassembly of section .ARM.attributes:
00000000 <.ARM.attributes>:
0: 00001341 andeq r1, r0, r1, asr #6
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 00000009 andeq r0, r0, r9
10: 01080106 tsteq r8, r6, lsl #2
Tested on a Raspberry Pi 3.
-
\$\begingroup\$ Somehow this doesn't work on a Pi 2. \$\endgroup\$univalence– univalence2017年03月05日 07:50:35 +00:00Commented Mar 5, 2017 at 7:50
Microsoft C (Visual Studio 2005 onwards), 16 bytes
main(){__ud2();}
I can't easily test this, but according to the documentation it should produce an illegal instruction by intentionally trying to execute a kernel-only instruction from a user-mode program. (Note that because the illegal instruction crashes the program, we don't have to try to return from main, meaning that this K&R-style main function is valid. Visual Studio never having moved on from C89 is normally a bad thing, but it came in useful here.)
-
\$\begingroup\$ Can you compile for linux with VS2015? Because I do not think SIGILL is defined in Windows, is it? \$\endgroup\$Andrew Savinykh– Andrew Savinykh2016年11月22日 03:59:22 +00:00Commented Nov 22, 2016 at 3:59
Ruby, 13 bytes
`kill -4 #$$`
I guess it's safe to assume that we are running this from a *nix shell. The backtick literals runs the given shell command. $$ is the running Ruby process, and the # is for string interpolation.
Without calling the shell directly:
Ruby, 17 bytes
Process.kill 4,$$
ELF + x86 machine code, 45 bytes
This should be the smallest executable program on an Unix machine that throws SIGILL (due to Linux not recognizing the executable if made any smaller).
Compile with nasm -f bin -o a.out tiny_sigill.asm, tested on an x64 virtual machine.
Actual 45 bytes binary:
0000000 457f 464c 0001 0000 0000 0000 0000 0001
0000020 0002 0003 0020 0001 0020 0001 0004 0000
0000040 0b0f c031 cd40 0080 0034 0020 0001
Assembly listing (see source below):
;tiny_sigill.asm
BITS 32
org 0x00010000
db 0x7F, "ELF" ; e_ident
dd 1 ; p_type
dd 0 ; p_offset
dd $$ ; p_vaddr
dw 2 ; e_type ; p_paddr
dw 3 ; e_machine
dd _start ; e_version ; p_filesz
dd _start ; e_entry ; p_memsz
dd 4 ; e_phoff ; p_flags
_start:
ud2 ; e_shoff ; p_align
xor eax, eax
inc eax ; e_flags
int 0x80
db 0
dw 0x34 ; e_ehsize
dw 0x20 ; e_phentsize
db 1 ; e_phnum
; e_shentsize
; e_shnum
; e_shstrndx
filesize equ $ - $$
Disclaimer: code from the following tutorial on writing the smallest assembly program to return a number, but using opcode ud2 instead of mov: http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html
-
2\$\begingroup\$ I was gonna post a modified executable of that exact tutorial, but you beat me to it. This deserves to win; It's a true minimalist in the system resources sense (It requires no more than 45 bytes both in-file and in-memory, and is exactly the same in both), and no bloated interpreter like the other assembler solutions. It simply is what it is. \$\endgroup\$Iwillnotexist Idonotexist– Iwillnotexist Idonotexist2016年11月27日 07:12:06 +00:00Commented Nov 27, 2016 at 7:12
AutoIt, 93 bytes
Using flatassembler inline assembly:
#include<AssembleIt.au3>
Func W()
_("use32")
_("ud2")
_("ret")
EndFunc
_AssembleIt("int","W")
When run in SciTE interactive mode, it'll crash immediately. The Windows debugger should popup for a fraction of a second. The console output will be something like this:
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
0x0F0BC3
!>14:27:09 AutoIt3.exe ended.rc:-1073741795
Where -1073741795 is the undefined error code thrown by the WinAPI. This can be any negative number.
Similar using my own assembler LASM:
#include<LASM.au3>
$_=LASM_ASMToMemory("ud2"&@CRLF&"ret 16")
LASM_CallMemory($_,0,0,0,0)
Any shell (sh, bash, csh, etc.), any POSIX (10 bytes)
Trivial answer but I hadn't seen anyone post it.
kill -4 $$
Just sends SIGILL to the current process. Example output on OSX:
bash-3.2$ kill -4 $$
Illegal instruction: 4
-
\$\begingroup\$ You could do
kill -4 1if the question isn't specific about which program throws the SIGILL \$\endgroup\$Mark K Cowan– Mark K Cowan2016年11月22日 23:06:04 +00:00Commented Nov 22, 2016 at 23:06 -
\$\begingroup\$ @MarkKCowan Heh, good point, although that assumes root... \$\endgroup\$fluffy– fluffy2016年11月23日 01:18:54 +00:00Commented Nov 23, 2016 at 1:18
-
2\$\begingroup\$
You will have root in your programs- knock a byte off your answer and troll the question slightly at the same time :D. BONUS: You get to killinit\$\endgroup\$Mark K Cowan– Mark K Cowan2016年11月23日 12:52:27 +00:00Commented Nov 23, 2016 at 12:52 -
2\$\begingroup\$ @MarkKCowan: On (modern versions of?) Linux,
initis actually immune to signals that it hasn't specifically requested to receive, even with root. You could perhaps work around this by using a different POSIX OS, though. \$\endgroup\$user62131– user621312016年11月23日 21:09:33 +00:00Commented Nov 23, 2016 at 21:09 -
2\$\begingroup\$
kill -4 2then :D \$\endgroup\$Mark K Cowan– Mark K Cowan2016年11月23日 21:11:11 +00:00Commented Nov 23, 2016 at 21:11
Python, 32 bytes
from os import*;kill(getpid(),4)
-
1\$\begingroup\$ Same byte count:
import os;os.kill(os.getpid(),4)\$\endgroup\$Oliver Ni– Oliver Ni2016年11月21日 20:02:49 +00:00Commented Nov 21, 2016 at 20:02
NASM, 25 bytes
I don't know how this works, just that it does on my computer specifically (Linux x86_64).
global start
start:
jmp 0
Compile & run like:
$ nasm -f elf64 ill.asm && ld ill.o && ./a.out
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400080
Illegal instruction
-
\$\begingroup\$ You can probably shorten it to four bytes, as
ja 0\$\endgroup\$Mark K Cowan– Mark K Cowan2016年11月23日 12:57:21 +00:00Commented Nov 23, 2016 at 12:57 -
1\$\begingroup\$ or three as
ud2\$\endgroup\$Mark K Cowan– Mark K Cowan2016年11月23日 12:58:23 +00:00Commented Nov 23, 2016 at 12:58 -
2\$\begingroup\$ Probably because it's trying to jump to some data? \$\endgroup\$asu– asu2016年11月23日 18:06:51 +00:00Commented Nov 23, 2016 at 18:06
TI-83 Hex Assembly, 2 bytes
PROGRAM:I
:AsmPrgmED77
Run as Asm(prgmI). Executes the illegal 0xed77 opcode. I count each pair of hex digits as one byte.
Linux shell, 9 bytes
kill -4 0
Sends SIGILL to the process with PID 0. I don't know what process has PID 0, but it always exists.
-
3\$\begingroup\$ From
man kill:0 All processes in the current process group are signaled.\$\endgroup\$Dennis– Dennis2018年02月27日 04:17:06 +00:00Commented Feb 27, 2018 at 4:17
x86 .COM, 1 byte
c
ARPL causes #UD in 16-bit mode
Rust, 53 bytes
fn main(){unsafe{std::hint::unreachable_unchecked()}}
This piece of code generates no main function because main is marked as unreached, hence SIGILL being triggered when run. Try it online!
-
2\$\begingroup\$ Welcome to Code Golf and Programming Puzzles stack exchange! You have a nice first answer, but is preferable to add a link to try it online. Also, your answer is only 53 bytes long. \$\endgroup\$Aiden4– Aiden42021年01月29日 16:44:59 +00:00Commented Jan 29, 2021 at 16:44
-
\$\begingroup\$ 41 bytes \$\endgroup\$ceilingcat– ceilingcat2025年06月20日 07:49:31 +00:00Commented Jun 20 at 7:49
GNU C, (削除) 24 (削除ここまで) (削除) 19 (削除ここまで) 18 bytes
-4 thanks to Dennis
-1 thanks to ceilingcat
main(){goto*&"'";}
Try it online! This assumes ASCII and x86_64. It attempts to run the machine code 27, which ... is illegal.
shortC, (削除) 10 (削除ここまで) (削除) 5 (削除ここまで) 4 bytes
AV"'
Equivalent to the GNU C code above. Try it online!
-
\$\begingroup\$
L"6円"is also illegal, assuming x86_64. \$\endgroup\$Dennis– Dennis2018年02月27日 04:20:26 +00:00Commented Feb 27, 2018 at 4:20 -
\$\begingroup\$ @Dennis What instruction is 0x06? Also, the
Lis not necessary. \$\endgroup\$MD XF– MD XF2018年02月27日 16:52:40 +00:00Commented Feb 27, 2018 at 16:52 -
\$\begingroup\$ It's unassigned. \$\endgroup\$Dennis– Dennis2018年02月27日 17:15:50 +00:00Commented Feb 27, 2018 at 17:15
-
\$\begingroup\$ It's unassigned; that's what makes it illegal. Also,
'is 39 = 0x27, not 0x39. \$\endgroup\$Dennis– Dennis2018年03月02日 03:49:08 +00:00Commented Mar 2, 2018 at 3:49
MachineCode on x86_64, (削除) 2 (削除ここまで) 1 bytes
7
Simply calls the x86_64 instruction 0x07 (ceilingcat suggested 0x07 instead of 0x27)
Swift 6 (non-competing)
So, uh...
@MainActor func mainActorOnly() {
print("Hi from the main actor!")
}
// implicitly `nonisolated`
func doStuff() async {
DispatchQueue.main.async { @MainActor in
MainActor.assertIsolated()
mainActorOnly()
}
}
await doStuff()
// MARK: - The WTF-level stuff
struct DispatchQueue {
static let main = Self()
func async(_ work: () -> Void) { work() }
}
This crashes with a SIGILL caused by a call to fatalError(_:file:line:) in MainActor.assertIsolated().
Details
Credit goes to this blog post for documenting this behavior. The following explanation assumes at least a basic understanding of Swift concurrency — in particular, what the "main actor" is, and what it means for code to be isolated to it.
This is a kinda big but also extremely silly hole in the implementation of Swift's concurrency model.
In short, there isn't actually any way for the compiler to prove that the closure passed to DispatchQueue.main.async (the real one from Foundation, not the impostor here) is guaranteed to be isolated to the main actor. So the type checker performs a syntax-level check for a closure passed to something called DispatchQueue.main.async, and will annotate the closure's type with @_unsafeMainActor if the check succeeds. (It should go without saying that this attribute does not perform any runtime checks on its own.)
To illustrate this, here's an example. This compiles and runs just fine (assuming that Foundation is imported, and that mainActorOnly() is a function annotated with @MainActor):
Task {
DispatchQueue.main.async {
mainActorOnly()
}
}
but these don't:
Task {
let queue = DispatchQueue.main
queue.async {
mainActorOnly() // error: call to main actor-isolated global function 'mainActorOnly()' in a synchronous nonisolated context
}
}
Task {
typealias DQ = DispatchQueue
DQ.main.async {
mainActorOnly() // error: call to main actor-isolated global function 'mainActorOnly()' in a synchronous nonisolated context
}
}
This can be a little annoying, but it's not too tricky to work around when you need to. The real problem shows itself when you declare your own type named DispatchQueue, with its own static property called main and an instance method called async that takes a closure:
struct DispatchQueue {
static let main = Self()
func async(_ work: () -> Void) { work() }
}
Our impostor DispatchQueue.main.async is quite evidently not isolated to the main actor, neither at compile-time nor at runtime. But the Swift compiler is none the wiser, and will happily let you call main actor-isolated code via this method.
(The runtime, however, isn't quite so naive, and correctly determines that
the closure passed to the fake async is nonisolated — this is why MainActor.assertIsolated() crashes in this case.)
MMIXAL, 13 bytes
Main RESUME 2
RESUME is legal in all code; RESUME 1 throws a protection violation in user mode; any other argument throws an illegal instruction violation.
raise(SIGILL)? \$\endgroup\$Illegal instruction (core dumped). \$\endgroup\$