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,7 +2042,11 @@ begin
aFile.typ := IODiskFile; aFile.typ := IODiskFile;
aFile.mode := mode; aFile.mode := mode;
new(aFile.buffer); newOrNil(aFile.buffer);
if aFile.buffer = nil then
fileerror(aFile, IONoMem)
else
begin
aFile.bufpos := 0; aFile.bufpos := 0;
aFile.bufsize := DefaultBufSize; aFile.bufsize := DefaultBufSize;
aFile.needsflush := false; aFile.needsflush := false;
@ -2053,6 +2063,7 @@ begin
aFile.extentBlocks := extentSize div 512; 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,7 +2280,8 @@ begin
if volid > 0 then if volid > 0 then
begin begin
openvolumeid(volid); openvolumeid(volid, error);
if error = 0 then
slotno := findfile(volid, fname, dirs, error) slotno := findfile(volid, fname, dirs, error)
end end
else else

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;
if typeContainsString(memLoc.typ.pointedType^) then
emitClearAlloc(memLoc.typ.pointedType);
end;
emitCheckAlloc;
(*We need to call CLEARMEM when the allocated type (*We need to call CLEARMEM when the allocated type
contains strings. contains strings.
INITSTRING checks if the header is non-zero to see if INITSTRING checks if the header is non-zero to see if
the string is already initialized, and the allocated the string is already initialized, and the allocated
chunk might contain random data so it would look chunk might contain random data so it would look
like an initialized string. *) like an initialized string. *)
if typeContainsString(memLoc.typ.pointedType^) then
emitClearAlloc(memLoc.typ.pointedType);
end;
if checkNil then
emitCheckAlloc;
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