Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I get access violations using Mike Heydon's TStringBuilder class?

I am using a TStringBuilder class ported from .Net to Delphi 7.

And here is my code snippet:

procedure TForm1.btn1Click(Sender: TObject);
const
  FILE_NAME = 'PATH TO A TEXT FILE';
var
  sBuilder: TStringBuilder;
  I: Integer;
  fil: TStringList;
  sResult: string;
  randInt: Integer;
begin
  randomize;
  sResult := '';
  for I := 1 to 100 do
  begin
    fil := TStringList.Create;
    try
      fil.LoadFromFile(FILE_NAME);

      randInt := Random(1024);

      sBuilder := TStringBuilder.Create(randInt);
      try
        sBuilder.Append(fil.Text);
        sResult := sBuilder.AsString;
      finally
        sBuilder.free;
      end;

      mmo1.Text := sResult;
    finally
      FreeAndNil(fil);
    end;
  end;
  showmessage ('DOne');
end;

I am experiencing AV errors. I can alleviate the problem when I create memory with the size multiple by 1024, however sometimes it still occurs.

Am I doing something wrong?

like image 530
John Avatar asked Dec 22 '22 10:12

John


1 Answers

Your code is fine. The TStringBuilder code you're using is faulty. Consider this method:

procedure TStringBuilder.Append(const AString : string); 
var iLen : integer; 
begin 
  iLen := length(AString); 
  if iLen + FIndex > FBuffMax then _ExpandBuffer; 
  move(AString[1],FBuffer[FIndex],iLen); 
  inc(FIndex,iLen); 
end;

If the future length is too long for the current buffer size, the buffer is expanded. _ExpandBuffer doubles the size of the buffer, but once that's done, it never checks whether the new buffer size is sufficient. If the original buffer size is 1024, and the file you're loading is 3 KB, then doubling the buffer size to 2048 will still leave the buffer too small in Append, and you'll end up overwriting 1024 bytes beyond the end of the buffer.

Change the if to a while in Append.

like image 98
Rob Kennedy Avatar answered Dec 24 '22 02:12

Rob Kennedy