Edit read a file into a buffer it never checked the size of
Opening hello.asm showed a thirty one line file as three, one of them cut short. Opening it again hung the machine: the emulator kept running and nothing ever answered. Entry is the buffer a line is read into, and it is followed in memory by TextHead and ArenaFree - the head of the document, and the pointer its line allocator hands out. The loop that splits a file into lines copied characters in WITH NO BOUND AT ALL, so a 94 character line wrote thirteen bytes over both of them. The list head then pointed into the middle of the text and the allocator handed out an address inside the file, which is why the second open walked a list that led back into itself for ever. Typing was always safe. osReadLine is told how much room there is, so a new document behaved perfectly and a source file did not - which is exactly how the user found it, and why it looked like a mystery rather than a bug. The bound is there now, and the buffer is 128 characters: what a line is everywhere else on this machine, the same number configuration files use, rather than a second answer to a question already answered. hello.asm fits. A file with a longer line is REFUSED rather than shortened. This is an editor - a line cut on the way in would be written back cut, and the file damaged by having been looked at. It says so and exits with a status of one, which it can do since this afternoon; the file is byte identical afterwards, and the test checks that. Opened twice in the test, because once is not enough to see it: the first open does the damage and the second is what never returns. This is the third time this shape has turned up: a buffer written past its end into the variables that happened to follow it. The prompt walked off CwdText into the shell's own command names; the assembler's output ran into its label table. Every one was found by a person using the machine.
This commit is contained in:
@@ -464,7 +464,20 @@ Typed in as bytes, checked by disassembling it back, and run. It ends with `SWI
|
||||
|
||||
`Edit` is the first program on this machine that makes a file a person typed - every byte on every disk before it was put there by the host tool. It is line oriented in the manner of `ed`: `l` lists, `a` adds at the end, `i` and `c` and `d` take a line number, `w` writes and `q` stops.
|
||||
|
||||
It includes nothing but `services.asm` and `text.asm`: the filesystem and the console are the system's, asked for rather than carried. That is what brought `Edit` down from 4,941 bytes to 1,986 bytes without a line of its own logic changing - and the way that was checked is worth knowing, because the recorded output of the `cosmosEdit` test did not move by a single byte across the rewrite.
|
||||
It includes nothing but `services.asm` and `text.asm`: the filesystem and the console are the system's, asked for rather than carried. That is what brought `Edit` down from 4,941 bytes to 2,157 bytes without a line of its own logic changing - and the way that was checked is worth knowing, because the recorded output of the `cosmosEdit` test did not move by a single byte across the rewrite.
|
||||
|
||||
**A line it reads in is at most 128 characters**, the same length a line is everywhere else
|
||||
on this machine, and a file with a longer one is refused rather than opened. Refused rather
|
||||
than shortened, because this is an editor: a line cut on the way in would be written back
|
||||
cut, and the file damaged by having been looked at.
|
||||
|
||||
That limit was not there at all until a source file found it. The buffer is followed in
|
||||
memory by the head of the document and the pointer the line allocator hands out, so a 94
|
||||
character line wrote characters over both - a 31 line file opened as 3, and opening it a
|
||||
second time walked a list that led back into itself for ever, with the emulator still
|
||||
running and the machine never answering again. Typing a long line was always safe, because
|
||||
`osReadLine` is told how much room there is; only the file being read went unchecked, which
|
||||
is why a new document behaved and a source file did not.
|
||||
|
||||
It keeps the document as a **linked list of lines** rather than one buffer with newlines in it. Each line says where the next one is, how long it is, and then its bytes. Inserting is two pointers changed and nothing moved; with a flat buffer it would mean shifting every byte after the edit, on a machine whose only block move is a device asked politely. The price is that deleted lines are not reused, so a heavy session uses more room than the document needs and writing it out is what tidies up.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user