90

From Esolang
Jump to navigation Jump to search

90 is an esoteric programming language created by User:ais523 in 2015 (in a few minutes, after being inspired by some comments by hppavilion[1] on IRC). Unlike most programming languages, a 90 program does not run code, but rather destroys the code of other programs. The name is in hexadecimal, but is nonetheless pronounced "ninety".

Syntax

A 90 program consists of a sequence of patterns, which are themselves sequences of octets, expressed as two-nybble hexadecimal numbers in uppercase (e.g. 0 is expressed as 00, and 255 as FF). The octets within a single pattern are separated using horizontal whitespace; the patterns themselves are separated in the input using paragraph breaks.

At least one (and possibly as many as all) of the octets in each pattern are targets; this is represented in the source code by underlining them. Comments may also be included in the source code but must be written in italics.

Semantics

When run, a 90 program scans the memory of user-mode processes that it has permission to access, looking for sequences of octet in memory that form one of its patterns. When it finds such a pattern, it replaces each octet in memory that corresponds to a target from the pattern with the octet 90. After scanning all such accessible memory, the program exits.

Analysis

A 90 program clearly cannot do anything by itself. However, 90 is a no-op operation on the x86 range of processors, meaning that on those processors you can basically form a new program by deleting sections of other programs. The actual logic of a 90 program thus runs after it exits, and is effectively formed out of scavenged components that existed in other programs.

There are three main obstacles to writing arbitrary programs in 90. One is that you need enough other software running on the system that there are sufficiently many components available to cobble together into your desired program. Another is the lack of control over how your newly salvaged code starts running (because there is no obvious way to control the instruction pointer to start at any particular point). The other is that, to emulate programs written in a more normal style, you somehow need to restore the functionality of the programs you disrupted (otherwise, e.g., you don't have a "Hello, world! program", but a "Hello world and crash random other programs program"), after presumably forking a new process to perform the actual behaviour you wanted. Trying to determine the original code in question can be very difficult because all accessible instances of it have been deleted from memory (the obvious thing to do is to reload it from disk, but even that is not trivial because a program's memory image does not necessarily have to correspond to anything on disk).

It's unclear how to define portability of a 90 program, given that the behaviour of a program depends not only on the architecture of the processor (processors where 90 is substantially different from a no-op will be much harder to write for), but also the local conditions at the time it is run. A robust program will have its intended effect when run on a wide range of systems (note that not all the patterns need to aim at the same architecture; a sufficiently long pattern is unlikely to match on the wrong kind of system).

Running two different 90 programs at the same time is likely to cause problems due to race conditions.