Protecting dynamically-allocated memory in Glulx

I couldn’t find an extension which allows you to easily designate state as being protected from UNDO, RESTORE, and RESTART, so I’ve been working on writing one. For word values this is easy, and sufficient for my purposes, but I figured if I’m writing an extension I should support block values too (and tables of varying size). This would require dynamic memory allocation, but if I understand the Glulx spec (and the source code of Glulxe) correctly, using @protect on heap memory is legal. However, two problems arise.

First, since you can only protect one continuous range at a time (aargh!), you can’t protect a heap block without forgetting what its address is (at least without risking protecting memory you don’t want protected). This is not so hard to get around, since you only need a single extra word of protected memory: I’m thinking of stashing the address in the rock of a Glk object or two - disgusting, I know. For RESTORE I could use a file since you’re doing file I/O anyway, but for UNDO and RESTART I’d really rather not (besides, now it’s a challenge to see if I can do it without files…).

More seriously, while protecting some heap block B will keep its data from being modified, this could also corrupt the heap, since in the restored state some other blocks might be located in addresses which used to be part of B. And if the heap doesn’t extend as far as B, then nothing is corrupted but of course you can’t access B without getting a memory access error. The only way I can think of to get around this is the following awful process:

  1. Compute some bound B on how big the memory map could be after the restore:
    [list=a]
    [*] For RESTORE, open the save file and parse the memory chunk (sadness).
  2. For UNDO, keep track of the largest the memory map has ever been at a @saveundo point.
  3. For RESTART, keep track of how big the memory map was in the initial state.
    [/:m]
    [
    ] Allocate enough memory to force the memory map to expand beyond B by the amount of information you need to protect (say there are L bytes of it).[/:m]
    [
    ] Copy the state you want preserved into memory starting at B (this will not cause an error, since Glulx allows writing to anywhere in the memory map even if not part of a heap block), and @protect the range [B, B+L).[/*:m]
    [] Somehow stash the values of B and L where they can be recovered after the restore.[/:m]
    [] Perform the restore.[/:m]
    [] Extract B and L, and allocate enough memory to force the memory map to expand up to B+L (since @malloc does not change the contents of memory, the data will be preserved).[/:m]
    [] Read the data starting at B and put it back in its rightful place; release the extra allocated memory.
    [/
    :m][/list:o]

Can anyone think of a better way?

Actually, it looks like this won’t work: in step 6 it appears that Glulxe will realloc the entire memory map without attempting to preserve the protected region, and also write zeroes over the new part of the map (so I guess when the spec says @malloc “does not change… the contents of the memory map at all” it means the contents of the old part of the memory map).

This makes me think @protect really was intended only for non-heap memory. Is there no hope then?

It doesn’t seem like a very useful feature to me, especially if you can write to files. It would only be useful in small circumstances, in which case the author should group their data together to begin with.

Indeed, for keeping large amounts of data unaffected by restores, files are obviously the way to go. Really I was just wondering if Glulx provides an internal way to protect some arbitrary blob of data and recover it after a restore, since this seems more natural and useful to me than the “protect a fixed memory range that always has the same meaning” paradigm.

Sorry. The protect opcode was an early addition, well before I’d planned the heap business. (It was also long before I7.)

For a specific purpose, you’d use it by defining an I6 array of fixed length and stuffing your data in there. A general extension is more awkward.

Oh no problem - that makes sense.

Handling a fixed but unknown (to the extension) number of word values can be done quite elegantly, using Inform’s I6 invocation syntaxes to create a single array of the required length which you can then @protect. So with my extension all you need to do to protect any word value X (which could be a global variable, property, or table entry) is add one line:

A state protection rule: now X is the protected value of X.

I’ll make another post later to get feedback on the syntax and see if there are any features missing that people would like included. Since I can’t make a new topic in the Inform Extensions forum, I assume this is the correct place for such a post.