Here's some info on DOS NetHack's internals, because dwangoAC asked. I'll use the seed 1223790555 as an example, as it's the one I'm using for my testrun (it may not be the very best seed for the glitch, but it's definitely pretty close, and I'll need to know exactly what to look for to find one better).
Objects take up 60 bytes or more in memory, generated using malloc. Here's an annotated dump of the gauntlets of power in memory, that are autopickedup on turn 1 with the seed given (note that a number like 12 34 56 78 is actually 0x78563412 due to the endianness of the x86 processor):
GoP (at physical address 00C390B0):
00 00 00 00 nobj
The next object on the object chain. This is what the game uses to iterate through inventory, etc.. A glitch object isn't actually on any object chain, so this won't be checked when doing the glitch. This is, however, why you can't (for instance) make a glitch object into a real one by fumble-dropping it; it isn't in the inventory object chain (you'd need to glitch a different part of memory to do that), so the game panics as it can't find an object that ought to be in inventory.
00 00 00 00 vptrs
A backreference from the object to the next object on the same floor location, the container that contains it, or the monster that carries it. Never checked for a glitch object.
00 00 00 00 cobj
If this object is a container, its contents (an object chain). Doesn't matter otherwise.
1C 00 00 00 o_id
An arbitrary number, different from every object, used to see if two objects are the same or not.
1D ox
04 oy
The location of the object, last time it mattered. (Probably when it was last on the floor.) Doesn't matter for objects in inventory, and thus glitch objects.
8A 00 otyp
A code representing what sort of object the object is (0x008A = gauntlets of power).
1E 00 00 00 owt
The weight of the object in game-internal units. Doesn't matter for any commands you can actually give on a glitch object.
01 00 00 00 quan
The stack size of the object. Most objects, like gloves, don't stack.
00 spe
The magical qualities of the object; this is what's set to 0 by cancellation. For a weapon or armour, this is the object's enchantment. (If trying to cause a buffer overflow, you'd want to set this to a 3-digit number like +100, to get a bit of extra length.)
03 oclass
The general group of items that this item falls into (autopickup group, screen symbol); 03 is '[', armour. Note: the 3 or 4 bytes from here onwards are the best things to look for if trying to memory-search for a particular object; it's how I found the GoP in memory for the first place.
6F invlet
The letter that this object has in inventory, or had last time it was there. 6F is ASCII for 'o', the letter which the GoP gained in inventory immediately after being picked up. The game also uses this as a flag to see if an item has ever been in inventory (relevant when training pets, etc., although not for a glitch object).
00 oartifact
This object's artifact code. Used to distinguish Excalibur from a longsword that happens to be named Excalibur, etc.. (It's a common urban myth in the NetHack community that this isn't tracked by the game, because it prevents you naming an item to clash with an artifact name anyway, part of a well-known realtime exploit for determining the true identity of an item; but it really is tracked separately.) 00 means it isn't an artifact.
03 where
Where the game currently thinks the item is; 03 means inventory. Glitch objects tend to have 03 in this field (unless manipulated by the player), even though they aren't actually on the inventory chain.
00 timed
The number of in-game timers on this object, used to track when it, say, hatches or burns out. (The timers themselves are stored elsewhere.) Will generally be 0 for most objects.
20 bitfield1
00 bitfield2
00 bitfield3
00 bitfield4
32 bits which have separate meanings of their own. In order: cursed, blessed, on a shop bill, in a shop but not owned by it, formally identified, viewed while not blind, blessing/curse known, rustproofing level known, [2 bits] rust/fire/dilution damage level (also used for "blecch!"ing food), [2 bits] corrosion/rot damage level (also used for unreviving corpses), erodeproofing level, locked, trapped/poisoned, [3 bits] recharge count, lit (for lamps, etc.), greased, [2 bits] object refers to a monster (for tracking dead pets, etc), currently being used by game internals, immune to spells (used temporarily to stop items being affected twice by the same spell).
This is likely the most useful field for a TAS; in particular, "viewed while not blind" can be altered simply by pressing ) to view the object's name, changing a 00 in that location to a 20, as seen here. My current plan is to use this to overwrite a trailing NUL at the end of a string to a space, although it might require several memory allocations to pull off. There are other potential uses too, such as setting as many of the user-visible flags as possible to create a really long object name.
ignored padding: 00 00
00 00 00 00 corpsenm
An object-type-specific flag: the monster class number of the monster this item is a corpse of (if it's a corpse), the monster ID of the pet leashed to this item (if a leash), the number of times a spellbook has been read, or 1 for an unbottled potion coming from a sink rather than a bottle.
00 00 00 00 oeaten
For partially eaten food, how much is left to eat.
01 00 00 00 age
Gametime when this object was created. (This is responsible for the unfortunately unexploitable crash when you drop 0 gold pieces onto another stack of 0 gold pieces; averaging out the ages gives a division by zero.)
00 onamelth
The length of the user-specific name for this item (used to reallocate the item if the name is made longer).
ignored padding: 00
00 00 oxlth
The offset from the end of the object to its name. Nearly always 0 in actual play (except in weird cases like named pet corpses, where the info is put in between the end of the object and its name); however, if this is changed via glitch, the object will take its name from an unexpected place in memory, which might help to gain unusually long names. (It's a signed 16-bit number, so you can even take names from earlier in memory than the object itself.)
00 00 00 00 wornmask
The parts of the body on which this item is currently being worn; redundant to things like the uwep pointer. This ends up out of synch with reality when the glitch is performed, stating that an item that isn't even in inventory is held in the hands.
00... oextra
Other things tacked onto the object, like its name or information on a monster that was converted into an item somehow. The number of bytes allocated here may vary; NetHack uses the "struct hack" famous among C programmers.
The memory allocation algorithm used by NetHack is DJGPP's standard algorithm: memory is looked for in this order:
- space left over in a block after it had to be split to allocate a small space from a large block (only one of these spaces is tracked at a time);
- freed blocks whose size is large enough to fit the requested size, and less than 5/4 the requested size, and has the same number of bits in its size (the most recently freed block is checked first);
- freed blocks which are large enough to fit the requested size (checked in order of number of bits in their size, and from most recently to least recently freed in order);
- memory requested from the OS.
When a block is freed, it's merged with other adjacent freed blocks (two blocks are adjacent if the distance between them is equal to the size of the first plus 8) into a larger block; if a block is allocated but has more than 64 bytes spare, the spare area is put into the "space left over" variable, and the old value of that variable is just marked as free, as normal.
For memory watching purposes: while a block of memory is allocated, the 4 bytes preceding it hold its size, and the 4 bytes following it also hold its size (so that blocks can be traversed forwards or backwards), and that's the only tracked metadata. While a block is deallocated, the sizes are still there (but with their low bit set to 1 to mark it as free); also, its first 4 bytes hold a pointer to the next block, its next 4 bytes cache the number of bits in its size (0 means 2 bits as in 2 or 3 bytes, 1 means 3 bits as in 4-7 bytes, 2 means 4 bits as in 8-15 bytes, and so on). (Allocated sizes are rounded up to a multiple of 8 so that the info in question fits.)