Compare commits

...

2 commits

Author SHA1 Message Date
slederer
52f82fe6ae runtime: bugfix stack corruption in MEMAVAIL 2025-08-31 23:31:00 +02:00
slederer
14d6de059d implement newOrNil, changes to stdlib
- newOrNil works like new, but sets the variable to nil
  if the heap allocation failed
- change stdlib to use newOrNil in openfile and openvolumeid
- changes to programs that use openvolumeid
2025-08-31 23:30:40 +02:00
11 changed files with 69 additions and 48 deletions

View file

@ -193,7 +193,8 @@ Possible error codes from _IOResult_ are:
| 8 | IOReadOnly | file is readonly | | | 8 | IOReadOnly | file is readonly | |
| 9 | IOInvalidOp | invalid operation | | | 9 | IOInvalidOp | invalid operation | |
| 10 | IOInvalidFormat | invalid format | when parsing numbers with _read_ | | 10 | IOInvalidFormat | invalid format | when parsing numbers with _read_ |
| 11 | IOUserIntr | interrupted by user | program terminated by ^C, not visible from _IOResult_ | | 11 | IONoMem | not enough memory | heap allocation failed inside the standard library, e.g. open() |
| 12 | IOUserIntr | interrupted by user | program terminated by ^C, not visible from _IOResult_ |
### Read, Readln and Line Input ### Read, Readln and Line Input
In Turbo Pascal, using _read_ (and _readln_) from the console always waits until a complete line has been entered. In Turbo Pascal, using _read_ (and _readln_) from the console always waits until a complete line has been entered.

View file

@ -612,6 +612,9 @@ WAIT1LOOP:
; length must be multiple of wordsize. ; length must be multiple of wordsize.
; if it is not, the last (partial) word is not cleared. ; if it is not, the last (partial) word is not cleared.
_CLEARMEM: _CLEARMEM:
OVER ; check for null pointer
CBRANCH.Z CLEARMEM_X
SHR SHR
SHR ; calculate length in words SHR ; calculate length in words

View file

@ -1787,6 +1787,7 @@ MAV_L:
CMPU NE CMPU NE
CBRANCH MAV_L ; if not equal, loop CBRANCH MAV_L ; if not equal, loop
MAX_XT: MAX_XT:
DROP ; drop chunk ptr
LOAD 0 ; put result value on stack LOAD 0 ; put result value on stack
FPADJ 4 FPADJ 4
RET RET

View file

@ -18,8 +18,9 @@ const IONoError = 0;
IOReadOnly = 8; IOReadOnly = 8;
IOInvalidOp = 9; IOInvalidOp = 9;
IOInvalidFormat = 10; IOInvalidFormat = 10;
IOUserIntr = 11; IONoMem = 11;
IOMaxErr = 11; IOUserIntr = 12;
IOMaxErr = 12;
const PArgMax = 7; const PArgMax = 7;
@ -206,7 +207,7 @@ procedure readvolumeblks(volumeid:integer; destbuf:^iobuffer; blkno:integer; blk
procedure writevolumeblks(volumeid:integer; srcbuf:^iobuffer; blkno:integer; blkCount: integer; var error:integer); procedure writevolumeblks(volumeid:integer; srcbuf:^iobuffer; blkno:integer; blkCount: integer; var error:integer);
external; external;
function findvolume(name:string):integer; external; function findvolume(name:string):integer; external;
procedure openvolumeid(volid:integer); external; procedure openvolumeid(volid:integer;var error:integer); external;
procedure closevolumeid(volid:integer); external; procedure closevolumeid(volid:integer); external;
function IOResult(var fil:file):integer; external; function IOResult(var fil:file):integer; external;
function ErrorStr(err:integer):string; external; function ErrorStr(err:integer):string; external;

View file

@ -26,8 +26,9 @@ const IONoError = 0;
IOReadOnly = 8; IOReadOnly = 8;
IOInvalidOp = 9; IOInvalidOp = 9;
IOInvalidFormat = 10; IOInvalidFormat = 10;
IOUserIntr = 11; IONoMem = 11;
IOMaxErr = 11; IOUserIntr = 12;
IOMaxErr = 12;
const PArgMax = 7; const PArgMax = 7;
@ -133,7 +134,7 @@ var DefaultVolumeId:integer;
character to the runtime error routine character to the runtime error routine
which takes null-terminated strings. which takes null-terminated strings.
*) *)
var ioerrordesc: array [0..11] of string[20] = ( var ioerrordesc: array [0..IOMaxErr] of string[20] = (
'No error', 'No error',
'File not found', 'File not found',
'Volume not found', 'Volume not found',
@ -145,6 +146,7 @@ var ioerrordesc: array [0..11] of string[20] = (
'File is readonly', 'File is readonly',
'Invalid operation', 'Invalid operation',
'Invalid format', 'Invalid format',
'Not enough memory',
'Interrupted by user' 'Interrupted by user'
); );
@ -1554,13 +1556,17 @@ begin
end; end;
end; end;
procedure openvolumeid(volid:integer); procedure openvolumeid(volid:integer;var error:integer);
begin begin
error := 0;
with volumeTable[volid] do with volumeTable[volid] do
begin begin
if dirCache = nil then if dirCache = nil then
new(dirCache); newOrNil(dirCache);
openFilesCount := openFilesCount + 1; if dirCache <> nil then
openFilesCount := openFilesCount + 1
else
error := IONoMem;
end; end;
end; end;
@ -2036,23 +2042,28 @@ begin
aFile.typ := IODiskFile; aFile.typ := IODiskFile;
aFile.mode := mode; aFile.mode := mode;
new(aFile.buffer); newOrNil(aFile.buffer);
aFile.bufpos := 0; if aFile.buffer = nil then
aFile.bufsize := DefaultBufSize; fileerror(aFile, IONoMem)
aFile.needsflush := false; else
aFile.changed := false; begin
aFile.lastError := 0; aFile.bufpos := 0;
aFile.errorAck := false; aFile.bufsize := DefaultBufSize;
aFile.volumeid := volid; aFile.needsflush := false;
aFile.fileno := slotno; aFile.changed := false;
aFile.filpos := 0; aFile.lastError := 0;
aFile.bufStart := 1; aFile.errorAck := false;
aFile.size := dirslot.sizeBytes; aFile.volumeid := volid;
aFile.sizeExtents := dirslot.sizeBytes div extentSize + 1; aFile.fileno := slotno;
aFile.bufBlocks := DefaultBufBlocks; aFile.filpos := 0;
aFile.extentBlocks := extentSize div 512; aFile.bufStart := 1;
aFile.size := dirslot.sizeBytes;
aFile.sizeExtents := dirslot.sizeBytes div extentSize + 1;
aFile.bufBlocks := DefaultBufBlocks;
aFile.extentBlocks := extentSize div 512;
seek(aFile,0); seek(aFile,0);
end;
end; end;
procedure updatedirslot(var aFile:file); procedure updatedirslot(var aFile:file);
@ -2269,8 +2280,9 @@ begin
if volid > 0 then if volid > 0 then
begin begin
openvolumeid(volid); openvolumeid(volid, error);
slotno := findfile(volid, fname, dirs, error) if error = 0 then
slotno := findfile(volid, fname, dirs, error)
end end
else else
error := IOVolNotFound; error := IOVolNotFound;

View file

@ -43,7 +43,7 @@ type TokenType = (
ArrayType, RecordType, PointerType, StringCharType, EnumType, ArrayType, RecordType, PointerType, StringCharType, EnumType,
SetType, UnresolvedType ); SetType, UnresolvedType );
SpecialProc = ( NoSP, NewSP, DisposeSP, ReadSP, WriteSP, ReadlnSP, WritelnSP, SpecialProc = ( NoSP, NewSP, New0SP, DisposeSP, ReadSP, WriteSP, ReadlnSP, WritelnSP,
SetlengthSP, ValSP, StrSP, ExitSP ); SetlengthSP, ValSP, StrSP, ExitSP );
SpecialFunc = ( NoSF, TruncSF, FracSF, IntSF, SqrSF, SuccSF, PredSF, SpecialFunc = ( NoSF, TruncSF, FracSF, IntSF, SqrSF, SuccSF, PredSF,
OddSF, ChrSF, OrdSF, AbsSF); OddSF, ChrSF, OrdSF, AbsSF);
@ -291,7 +291,7 @@ var
'UNIT', 'IMPLEMENTATION', 'INTERFACE', 'USES', 'UNIT', 'IMPLEMENTATION', 'INTERFACE', 'USES',
'_' ); '_' );
specialprocnames: array [SpecialProc] of string[12] = ( specialprocnames: array [SpecialProc] of string[12] = (
'_', 'NEW', 'DISPOSE', 'READ', 'WRITE', 'READLN', 'WRITELN', 'SETLENGTH', '_', 'NEW', 'NEWORNIL', 'DISPOSE', 'READ', 'WRITE', 'READLN', 'WRITELN', 'SETLENGTH',
'VAL','STR', 'EXIT'); 'VAL','STR', 'EXIT');
specialfuncnames: array [SpecialFunc] of string[8] = ( specialfuncnames: array [SpecialFunc] of string[8] = (
'_', 'TRUNC', 'FRAC', 'INT', 'SQR', 'SUCC', 'PRED', 'ODD', '_', 'TRUNC', 'FRAC', 'INT', 'SQR', 'SUCC', 'PRED', 'ODD',
@ -4500,7 +4500,7 @@ begin
isFunction := aProc^.returnType.baseType <> NoType; isFunction := aProc^.returnType.baseType <> NoType;
end; end;
procedure parseNew; procedure parseNew(checkNil:boolean);
var memLoc: MemLocation; var memLoc: MemLocation;
typeReturn: TypeSpec; typeReturn: TypeSpec;
begin begin
@ -4526,17 +4526,17 @@ begin
emitLoadConstantInt(memLoc.typ.pointedType^.size); emitLoadConstantInt(memLoc.typ.pointedType^.size);
emitMemAlloc; emitMemAlloc;
(*We need to call CLEARMEM when the allocated type
contains strings.
INITSTRING checks if the header is non-zero to see if
the string is already initialized, and the allocated
chunk might contain random data so it would look
like an initialized string. *)
if typeContainsString(memLoc.typ.pointedType^) then if typeContainsString(memLoc.typ.pointedType^) then
emitClearAlloc(memLoc.typ.pointedType); emitClearAlloc(memLoc.typ.pointedType);
end; end;
emitCheckAlloc; if checkNil then
emitCheckAlloc;
(*We need to call CLEARMEM when the allocated type
contains strings.
INITSTRING checks if the header is non-zero to see if
the string is already initialized, and the allocated
chunk might contain random data so it would look
like an initialized string. *)
writeVariable(memLoc); writeVariable(memLoc);
@ -5017,7 +5017,9 @@ begin
NoSP: NoSP:
errorExit2('internal error in parseSpecialProcCall', lastToken.tokenText); errorExit2('internal error in parseSpecialProcCall', lastToken.tokenText);
NewSP: NewSP:
parseNew; parseNew(true);
New0SP:
parseNew(false);
DisposeSP: DisposeSP:
parseDispose; parseDispose;
ReadSP: ReadSP:

View file

@ -14,8 +14,8 @@ var dirs:DirectorySlot;
error:integer; error:integer;
begin begin
lastSlot := volumeTable[volid].part.dirSize - 1; lastSlot := volumeTable[volid].part.dirSize - 1;
openvolumeid(volid); openvolumeid(volid, error); (* we just ignore error here because
we should always have enough heap space *)
for i := 0 to lastSlot do for i := 0 to lastSlot do
begin begin
getdirslot(volid, i, dirs, error); getdirslot(volid, i, dirs, error);

View file

@ -123,7 +123,8 @@ begin
freeAreaCount := 0; freeAreaCount := 0;
lastUsed := 0; lastUsed := 0;
openvolumeid(volid); openvolumeid(volid, error);
(* ignoring theoretically possible out-of-heap-error *)
i := 0; i := 0;
endSlot := volumeTable[volid].part.dirSize - 1; endSlot := volumeTable[volid].part.dirSize - 1;
@ -308,7 +309,7 @@ begin
writeln('Volume ', volname, ' not found.') writeln('Volume ', volname, ' not found.')
else else
begin begin
openvolumeid(volid); openvolumeid(volid, error);
endSlot := volumeTable[volid].part.dirSize - 1; endSlot := volumeTable[volid].part.dirSize - 1;
extentSize := volumeTable[volid].part.extentSize; extentSize := volumeTable[volid].part.extentSize;

View file

@ -102,8 +102,8 @@ begin
count := PageMargin; count := PageMargin;
lastSlot := volumeTable[volid].part.dirSize - 1; lastSlot := volumeTable[volid].part.dirSize - 1;
openvolumeid(volid); openvolumeid(volid, error);
(* ignoring theoretically possible out-of-heap-space error *)
for i := 0 to lastSlot do for i := 0 to lastSlot do
begin begin
getdirslot(volid, i, dirs, error); getdirslot(volid, i, dirs, error);

View file

@ -149,7 +149,7 @@ begin
count := PageMargin; count := PageMargin;
writeln('reading directory of ', DefaultVolume); writeln('reading directory of ', DefaultVolume);
openvolumeid(volid); openvolumeid(volid, error);
readdirfirst(volid, index, dirs, error); readdirfirst(volid, index, dirs, error);
while index > 0 do while index > 0 do
begin begin

View file

@ -398,7 +398,7 @@ begin
writeln('Volume ', DefaultVolume, ' not found.') writeln('Volume ', DefaultVolume, ' not found.')
else else
begin begin
openvolumeid(volid); openvolumeid(volid, error);
readdirfirst(volid, index, dirs, error); readdirfirst(volid, index, dirs, error);
while (index > 0) and (error = 0) do while (index > 0) and (error = 0) do
begin begin