I have a program:
program OverflowTest;
var
src: file;
dest: file;
res: longint;
buf: byte;
begin
assign(src, '48_bytes_file.txt');
assign(dest, 'copy_of_48_bytes_file.txt');
reset(src, 2);
rewrite(dest, 2);
BlockRead(src, buf, 24, res);
BlockWrite(dest, buf, 24, res);
close(src);
close(dest);
end.
Here I am reading 48 bytes of data into the variable buf
, which can only contain one byte (because it is of type byte
). And it works. The data is successfully copied to the second file without data loss.
Why can I write 48 bytes of data to a 1 byte variable? Why there are no errors like "memory overflow", "invalid buffer size"?
There are no errors because blockRead
and blockWrite
are by design unsafe.
The signature of blockRead
reads
procedure BlockRead(var f: file; var Buf; count: Word; var Result: Word)
Note the absence of a data type for Buf
.
This Borland Pascal extension means that any data type is permissible, only var
restricts it to variables.
For untyped parameters only the memory address of the (beginning of the) variable is passed, the data type byte
is lost.
BlockRead
and blockWrite
can therefore be deemed UCSD Pascal’s equivalent to C’s read
and write
suffering from the same kind of anomaly.
You as the programmer/user of routines accepting so‑called “untyped parameters” need to pay attention for mistakes like this one you experienced.
You do not observe any strange effects or crashes, because in all your tests the memory space following buf
is apparently not used by something else and belongs to your program.
Let’s apply following changes to your test program:
buf
:
program overflowTest(input, output, stdErr);
var
src, dest: file;
res: longInt;
buf: byte;
fer: byte;
48_bytes_file.txt
.
begin
fer := 0;
{ and the remaining program unchanged }
fer
visible.
{ … }
writeLn(fer)
end.
When compiling and running the modified program, you may† notice that writeLn(fer)
does not write 0
, the value we initialized fer
with.
This means
var
variables next to each in memory, andblockRead
bluntly writes 48 bytes to memory starting at the location of buf
and beyond without regard to the size of buf
.As a consequence you cannot use fer
productively.
If your program relies on fer
being 0
, the intervening blockRead
overwrote the 0
.
†: I have tested the behavior only for an x86-64 Linux target.