Frank Heckenbach wrote:
Strange! There has always been a check for the maximum length in the read[ln] procedure.
On the other hand, Read (F, stringVar) only reads a maximum of Length(stringVar) characters [as it should].
Even more strange, since Read and Readln are actually the same procedure (or rather function) internally. Readln (F, stringVar) first does exactly the same as Read (F, stringVar), and then a Readln (stringVar).
Perhaps you did some other thing in your program that triggered the first bug? If not, please send me a program and sample input to show this problem.
MY MISTAKE! Read[ln] work correctly and never exceeds the string capacity, and my problems are totally UNrelated to the missing range checks in some string expressions that I mentioned in the original post.
The strange crash in my program was indeed caused by writing to memory beyond the string capacity (that is, overwriting something else), but I was jumping to conclusions in blaming Readln. The real culprit was my own buggy code (specifically, a procedure that added a #0 to the string ...).
ADVICE TO GPC USERS:
If you add #0 to a string (in order to call functions in the C library), it is a *very* good idea to use strings whose capacity (max length) are not divisible by 4. In that case, at least one byte is "wasted" to achieve 4-byte alignment, and adding #0 should not overwrite other variables. Alternatively, you should explicitly check that the entire capacity is not used before adding the #0 char, like the procedure below which safely adds #0, and returns a Cstring variable (pointer) to the string.
Regards,
Jesper Lund
function Get_Cstring (var s : string) : Cstring; var p : Cstring; sLen : Integer;
begin sLen := Length (s);
if (slen = s.Capacity) then { We are about to crash .... } begin Writeln ('Fatal error in Get_Cstring: string too short'); Halt; end; { if }
p := Cstring (@s[1]); { Generates same code as: p := s } p[sLen] := #0; { Note: This overwrites s[sLen+1] with #0 }
Get_Cstring := p; { Return pointer to first element } end; { Get_Cstring }