[fpc-devel] DatabaseError/DatabaseErrorFmt with Component parameter, TParams.GetByName

Bram Kuijvenhoven kuifwaremailinglists at xs4all.nl
Mon Sep 26 14:10:07 CEST 2005


Hi FPC,

I found that using a TParams.GetByName call using an invalid parameter name causes a crash when the TParams is not owned by a TDataset.

I'm not sure whether it is a requirement of TParams usage to have it owned by a TDataset object, but otherwise, below is an explanation of what is going wrong.


Now the details about the crash. Start by looking at

dsparams.inc, lin 146 to 151:

  Function TParams.ParamByName(const Value: string): TParam;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      DatabaseErrorFmt(SParameterNotFound,[Value],Dataset);
  end;

If no parameter with name Value is found, it calls DatabaseErrorFmt with its formal parameter Component getting the value that Dataset returns. Look at TParams.GetDataSet:

dsparams.inc, line 32 to 38:

  Function TParams.GetDataSet: TDataSet;
  begin
    If (FOwner is TDataset) Then
      Result:=TDataset(FOwner)
    else
      Result:=Nil;
  end;

As you can see, Dataset will take value nil if the TParams instance has no Owner. Now look at DatabaseErrorFmt:

db.pp, line 1823 to 1827:

  Procedure DatabaseErrorFmt (Const Fmt : String; Args : Array Of const;
                              Comp : TComponent);
  begin
    Raise EDatabaseError.CreateFmt(Format('%s : %s',[Comp.Name,Fmt]),Args);
  end;

No check is done on Assigned(Comp), so the dereferencing Comp.Name will cause an Access Violation (instead of a nice 'Parameter blablabla not found' message).


Perhaps we should fix TParams.ParamByName to

  Function TParams.ParamByName(const Value: string): TParam;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      begin
      if DataSet<>nil then
        DatabaseErrorFmt(SParameterNotFound,[Value],DataSet)
      else
        DatabaseErrorFmt(SParameterNotFound,[Value]);
      end;
  end;

or

  Function TParams.ParamByName(const Value: string): TParam;
  var
    TmpDataset:TDataset;
  begin
    Result:=FindParam(Value);
    If (Result=Nil) then
      begin
      TmpDataSet:=DataSet;
      if TmpDataSet<>nil then
        DatabaseErrorFmt(SParameterNotFound,[Value],TmpDataset)
      else
        DatabaseErrorFmt(SParameterNotFound,[Value]);
      end;
  end;


Regards,

Bram Kuijvenhoven



More information about the fpc-devel mailing list