3v4l.org

run code in 300+ PHP versions simultaneously
<?php namespace Demo; class OutOfMemory extends \Exception {} class InvalidFree extends \Exception {} // This is the system heap, this system only has 128 bytes of memory available to applications const HEAP_SIZE = 128; $heap = "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF"; // The operating system allocator keeps track of the memory block that have been allocated to each application $blocks = []; function malloc($size) { global $blocks; $newPtr = 0; foreach ($blocks as $ptr => $size) { // If the gap between $newPtr and the start of this block is big enough to fit the request size, // allocate the block in between if ($newPtr + $size <= $ptr) { $blocks[$newPtr] = $size; return $newPtr; } $newPtr = $ptr + $size; } // Check if there's enough space at the end // When allocating at the end, verify that the requested size won't overflow the heap if ($newPtr + $size <= HEAP_SIZE) { $blocks[$newPtr] = $size; return $newPtr; } // There was not a large enough contiguous block on the heap to allocate the requested size throw new OutOfMemory; } function free($ptr) { global $blocks; // Can only free a complete block that has been allocated (can't free a partial one) if (!isset($blocks[$ptr])) { throw new InvalidFree; } unset($blocks[$ptr]); } // strcpy() is an example of a function that works with C strings and relies on the presence of a null terminator function strcpy($dstPtr, $srcPtr) { global $heap; for ($i = 0; $heap[$srcPtr + $i] !== "\0"; $i++) { $heap[$dstPtr + 0] = $heap[$srcPtr + $i]; } } // Output an arbitrary block from the heap // Notice that this requires a length argument so it knows when to stop function output($ptr, $len) { global $heap; for ($i = 0; $ptr + $i < HEAP_SIZE && $i < $len; $i++) { echo $heap[$ptr + $i]; } // This is just here to make the output readable echo "\n\n"; } // Output a string // No length argument here, so it must be a valid string function output_string($ptr) { global $heap; for ($i = 0; $ptr + $i < HEAP_SIZE && $heap[$ptr + $i] !== "\0"; $i++) { echo $heap[$ptr + $i]; } // This is just here to make the output readable echo "\n\n"; } $myString = malloc(14); $heap[$myString + 0] = 'h'; $heap[$myString + 1] = 'e'; $heap[$myString + 2] = 'l'; $heap[$myString + 3] = 'l'; $heap[$myString + 4] = 'o'; $heap[$myString + 5] = ','; $heap[$myString + 6] = ' '; $heap[$myString + 7] = 'w'; $heap[$myString + 8] = 'o'; $heap[$myString + 9] = 'r'; $heap[$myString + 10] = 'l'; $heap[$myString + 11] = 'd'; $heap[$myString + 12] = '!'; $heap[$myString + 13] = "\0"; // fine, this is a valid string, it has a null terminator output_string($myString); $arbitraryBlock = malloc(1); $heap[$arbitraryBlock] = '#'; // fine, we gave it a sensible length output($arbitraryBlock, 1); // but if we do this, we get an overflow and it keeps going until it encounters the next null byte or the end of the heap output_string($arbitraryBlock); // things can get weirder when stuff like this happens free($myString); // release the memory back to the OS $newString = malloc(9); // this will end up reallocating the same block $heap[$newString + 0] = 'H'; $heap[$newString + 1] = 'i'; $heap[$newString + 2] = ' '; $heap[$newString + 3] = 't'; $heap[$newString + 4] = 'h'; $heap[$newString + 5] = 'e'; $heap[$newString + 6] = 'r'; $heap[$newString + 7] = 'e'; // oops! no null terminator output_string($newString);
Output for 7.0.0 - 7.0.20, 7.1.0 - 7.1.33, 7.2.0 - 7.2.33, 7.3.0 - 7.3.33, 7.4.0 - 7.4.33, 8.0.0 - 8.0.30, 8.1.0 - 8.1.33, 8.2.0 - 8.2.29, 8.3.0 - 8.3.25, 8.4.1 - 8.4.12
hello, world! # #F0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF Hi thereorld!

preferences:
194.81 ms | 408 KiB | 5 Q