AV in BookmarkValid
Posted: Thu  11 Apr 2013 05:51
				
				Hello,
I have problem with TMSQuery.BookmarkValid method - Access violation.
I use SDAC 6.6.12 with source code under Windows 7 and Delphi XE.
I prepared test project for AV demonstration. It contains these files:
Project1.dpr
Unit1.pas
Unit1.dfm
MemMgr.pas
Just click on Button2.
Regards
Martin Kolek
Project1.dpr
Unit1.pas
Unit1.dfm
MemMgr.pas
			I have problem with TMSQuery.BookmarkValid method - Access violation.
I use SDAC 6.6.12 with source code under Windows 7 and Delphi XE.
I prepared test project for AV demonstration. It contains these files:
Project1.dpr
Unit1.pas
Unit1.dfm
MemMgr.pas
Just click on Button2.
Regards
Martin Kolek
Project1.dpr
Code: Select all
program Project1;
uses
  MemMgr in 'MemMgr.pas',
  Forms,
  Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
Code: Select all
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, DB, MemDS, DBAccess, MSAccess;
type
  TForm1 = class(TForm)
    Connection: TMSConnection;
    Query: TMSQuery;
    Button2: TButton;
    Label3: TLabel;
    lPocet2: TLabel;
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
uses
  MemData;
{$R *.dfm}
procedure TForm1.Button2Click(Sender: TObject);
  function __GetQueryStr(PocetZaznamu: integer): string;
    function __RandomChar: string;
    begin
      Result := Chr(65 + Random(26));
    end;
    function __RandomWord(PocetPismen: integer): string;
    var
      i: integer;
    begin
      Result := '';
      for i := 0 to PocetPismen - 1 do
        Result := Result + __RandomChar;
    end;
  var
    i: integer;
  begin
    Randomize;
    Result := 'SELECT * FROM (';
    for i := 0 to PocetZaznamu - 1 do
    begin
      if i = 0 then
        Result := Result +
          Format(
            '(SELECT %d AS Field1, ''%s'' AS Field2, ''%s'' AS Field3, ''%s'' AS Field4)',
            [Random(1000),
             __RandomWord(3),
             __RandomWord(2),
             __RandomWord(1)])
      else
        Result := Result +
          Format(
            '(SELECT %d, ''%s'', ''%s'', ''%s'')',
            [Random(1000),
             __RandomWord(3),
             __RandomWord(2),
             __RandomWord(1)]);
      if i < (PocetZaznamu - 1) then
        Result := Result + ' UNION ALL'#13
    end;
    Result := Result + ') t';
  end;
var
  i: integer;
  S: string;
  B: TBookmark;
begin
  for i := 1 to 100 do
  begin
    Connection.Connect;
    Query.SQL.Text := __GetQueryStr(200);
    Query.Open;
    Query.Last;
    B := Query.Bookmark;
    Query.Close;
    Query.SQL.Text := __GetQueryStr(50);
    Query.Open;
    if not Query.BookmarkValid(B) then ; // AV here. Bookmark.Item is the dangling pointer
    lPocet2.Caption := IntToStr(StrToIntDef(lPocet2.Caption, 0) + 1);
    lPocet2.Refresh;
  end;
end;
end.
Code: Select all
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 335
  ClientWidth = 396
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object Label3: TLabel
    Left = 80
    Top = 150
    Width = 107
    Height = 13
    Caption = 'AV with BookmarkValid'
  end
  object lPocet2: TLabel
    Left = 85
    Top = 75
    Width = 6
    Height = 13
    Caption = '0'
  end
  object Button2: TButton
    Left = 80
    Top = 170
    Width = 211
    Height = 71
    Caption = 'Button2'
    TabOrder = 0
    OnClick = Button2Click
  end
  object Connection: TMSConnection
    Authentication = auWindows
    Left = 25
    Top = 20
  end
  object Query: TMSQuery
    Connection = Connection
    Left = 60
    Top = 20
  end
end
Code: Select all
unit MemMgr;
interface
implementation
uses
  Windows;
{ Memory Management }
const
  HEAP_MAX_SIZE = $100000;
  HEAP_GENERATE_EXCEPTIONS = $00000004;
  HEAP_NO_SERIALIZE = $00000001;
  HEAP_ZERO_MEMORY = $00000008;
var
  PrivateHeap: THandle;
  SavedMemoryManager: TMemoryManager;
function InternalGetMem(Size: Integer): Pointer;
begin
  Result := HeapAlloc(PrivateHeap, HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY, Size);
end;
function InternalFreeMem(P: Pointer): Integer;
begin
  Result := Integer(not HeapFree(PrivateHeap, HEAP_NO_SERIALIZE, P))
end;
function InternalReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := HeapReAlloc(PrivateHeap, HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE or HEAP_ZERO_MEMORY, P, Size)
end;
const
  MemoryManager: TMemoryManager = (
    GetMem: InternalGetMem;
    FreeMem: InternalFreeMem;
    ReallocMem: InternalReallocMem
  );
initialization
  PrivateHeap := HeapCreate(HEAP_GENERATE_EXCEPTIONS or HEAP_NO_SERIALIZE, 0, HEAP_MAX_SIZE);
  GetMemoryManager(SavedMemoryManager);
  SetMemoryManager(MemoryManager);
finalization
  HeapDestroy(PrivateHeap);
  SetMemoryManager(SavedMemoryManager);
end.