Haskell, 49 bytes
import Unsafe.Coerce
main=putStr[unsafeCoerce(+)]
Unfortunately this seems to always outputs the same thing on TIO (I don't quite know why, but I have some guesses), so if you want to try it you should run it locally.
I've only tested this on Linux and OSX. I make no guarentees about Windows. If you are having trouble getting it to work on Linux I would be interested to know.
Explanation
What is unsafeCoerce
?
This answer relies on unsafeCoerce
. This function is a bit of magic, so first we are going to have to do a quick intro to Haskell's type system.
Haskell has something called type erasure. This means that the compiler checks all the types to make sure that nothing in the program is called on the wrong type. Once it is done with that there is no need to actually store type information any more, so Haskell erases it. So at runtime all data is the same and just relies on the fact that we already checked all the types before hand so nothing goes horribly wrong.
unsafeCoerce
is a function that lies to the type checker. It tells it that it can take any input and produce any output; it's type is
forall a. forall b. a -> b
But it does nothing, it gives back the input exactly as it got it. So if you take a string like "abcd"
and coerce it to an int using unsafeCoerce
the result will be whatever the representation of "abcd"
in memory is when interpreted as an integer.
How are functions represented in memory?
In Haskell, all complex objects including functions are internally represented as a pointer. This is a number in binary that "points" to a specific location in memory. This is because we want to pass these values by reference, since copying the whole thing is expensive, and since Haskell disallows mutation we can with no problem.
However simple objects like ints are passed by value since they are so small that copying them is about as expensive as copying a pointer would be. So they are not represented as pointers but rather just whatever structure they are.
So if we use unsafeCoerce
from a complex object, say a function, to a simple object, say an Int
, what happens is that the pointer to the function gets converted to the simple object. And the value of that simple object is dependent only on where the complex object is located not anything about what it is.
Address Space Layout Randomization
More reading
Many software vulnerabilities rely in part on being able to find particular functions in computer memory to access them. For these techniques you create some malicious code somewhere in memory (this can be done a few ways) and then by hijacking the stack pointer convince a program to run your code. In order to combat these exploits many systems implement something called Address Space Layout Randomization or ASLR. With ASLR key components are placed randomly so that their locations cannot be predicted. This means even if you do get control of the stack pointer it is hard to find where your malicious code is placed. ALSR is not the only technique used against these attacks but it is one we care about.
For Linux systems you can check of ASLR is on using
cat /proc/sys/kernel/randomize_va_space
Or since this is code-golf:
sysctl -anr "e_v"
There are three levels of security here 0
for off, and 1
and 2
for varying levels of on. My computer has this set to 2
(and your computer probably does too).
You can also set this. However do not do this unless you know what you are doing. Please do not mess with your kernel (unless you know what you are doing). For this reason I'm not going to include the command to do this, but you can look it up online or figure it out from the commands I already gave.
What this means for us is that the locations for objects allocated by Haskell at runtime is random or at least non-deterministic. This means that when we take a complex object like a function and convert it to a simple object like an Int
the value of that object is random too.
The program
So that's what our program does. We coerce a function, (+)
because it is short. We wrap this in a list and print it using putStr
. Since putStr
expects a string the compiler infers that the output of unsafeCoerce(+)
must be a Char
, which is a simple type.
So we end up printing a random one character string.