Russ Whitaker wrote:
tried program by Jo Dillon
changing the function GetMem to the procedure GetMem makes the problem go away
why i don't know
(* See my previous mail for the description of the problem. *)
When using the GetMem procedure, GPC seems to initialize the Capacity field. However, this is a misfeature, and needs to be turned off!
Sorry if that's unpopular, but here's the reason why: when the record contains a string (or any schema) in any position but the first, and the size requested from GetMem is smaller than the size of the fields before, the discriminants (here: Capacity) will be outside the allocated space, and must not be written to. The following version of the program demonstrates the problem. It will just allocate enough space for the first string (s), which would be sufficient for what the program does here. However, GPC's trying to initialize t and u will go outside the allocated memory -- I increased the size of the strings here, so that this will most likely result in a segfault.
program baby;
type BigString = String(200000);
type trec = record s, t, u : bigstring; end; prec = ^trec;
var r : prec;
begin GetMem(r, sizeof(bigstring)); r^.s := 'OK'; writeln (r^.s) end.
The bottom line here is that GetMem (as well as FillChar, for that matter) are low-level routines, and mixing them with (high-level) Pascal objects like schemata (e.g. Strings) or files, requires precise understanding of the internals, is non-portable (between compilers as well as between architectures) and should be avoided (here: by using New) whenever possible. It might even be worthwhile to think about disabling GetMem etc. by default to protect against such bugs, and enabling them only with a special switch (something like a "weaker `--extended-syntax'") and, of course, in `--borland-pascal'.
Now the good news as far as strings are concerned: BP compatible "short strings" are on the To-Do list, and when they will have been implemented, whenever this will be, such things like GetMem, even `GetMem (StringPtr, Length (StringVal) + 1); StringPtr^ := StringVal', FillChar, or accessing `StringVar [0]' to get and/or modify their length, will work with short strings, as they won't have a Capacity field.
Frank