Recent

Author Topic: Access Violation on Procedure Exit  (Read 4030 times)

Thaddy

  • Hero Member
  • *****
  • Posts: 16201
  • Censorship about opinions does not belong here.
Re: Access Violation on Procedure Exit
« Reply #15 on: May 29, 2024, 06:25:00 pm »
On Windows CE Pchar <> PAnsiChar but PUnicodeChar/PWideChar. Change all PChar declarations to explicit PAnsiChar and all Chars to explicit AnsiChar.
Last time I programmed for CE is a long time ago, so plz consider that an oversight.
CE is a unicode system since at least CE v6, which means that the string types are interpreted accordingly.
« Last Edit: May 29, 2024, 06:30:01 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1432
    • Lebeau Software
Re: Access Violation on Procedure Exit
« Reply #16 on: May 29, 2024, 07:13:39 pm »
Code: Pascal  [Select][+][-]
  1. ReadStringVar(btn[0]); // working, got Messagebox (last line of procedure (Line 202))
  2. ShowMessage('test'); // not working, got AV

That implies you are corrupting memory or the call stack.

Code: Pascal  [Select][+][-]
  1. function TfrmMain.PlcStringToString(APlcString: array of char): string;
  2. var
  3.   i: integer;
  4. begin
  5.   Result:= '';
  6.   for i:= 0 to length(APlcString) do begin
  7.     if APlcString[i] <> Chr($00) then
  8.       Result:= Result + APlcString[i]
  9.     else exit;
  10.   end;
  11. end;

This is a buffer overflow waiting to happen if APlcString is not null-terminated.  An open array is 0-indexed, so your loop needs to use length(APlcString)-1 (or High(APlcString)) instead, otherwise you go out of bounds.

Rather than doing a concatenation on every loop iteration, I would suggest using SetString() instead, eg:

Code: Pascal  [Select][+][-]
  1. function TfrmMain.PlcStringToString(APlcString: array of char): string;
  2. var
  3.   len: integer;
  4. begin
  5.   for len := 0 to Length(APlcString)-1 do begin
  6.     if APlcString[len] = Chr($00) then Break;
  7.   end;
  8.   SetString(Result, PChar(APlcString), len);
  9. end;

Alternatively:

Code: Pascal  [Select][+][-]
  1. function TfrmMain.PlcStringToString(APlcString: array of char): string;
  2. begin
  3.   SetString(Result, PChar(APlcString), Length(APlcString));
  4.   Result := TrimRight(Result);
  5. end;

Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.ReadStringVar(var aVar: TStringVar);
  2. var
  3.   tmp: array of char;
  4.   ads: longint;
  5. begin
  6.   if aVar.Handle = 0 then
  7.     ads:= AdsSyncReadWriteReq(@AMS, ADSIGRP_SYM_HNDBYNAME, $0000, sizeof(aVar.Handle), @aVar.Handle, Length(aVar.VarName) + 1, @aVar.VarName[1])
  8.   else ads:= 0;
  9.   SetLength(tmp, 255);
  10.   if ads = 0 then
  11.     ads:= AdsSyncReadReq(@AMS, ADSIGRP_SYM_VALBYHND, aVar.Handle, Length(tmp), @tmp[0]);
  12.   if ads = 0 then aVar.Data:= PlcStringToString(tmp);
  13.   ShowMessage('in Procedure: ' + aVar.Data);
  14. end;

There is no need to allocate tmp dynamically.

More importantly, a ShortString is not null-terminated, but you are passing in a pointer directly to its characters, and passing in +1 for its length as if a null terminator were present. You need to pass in a valid null-terminated string, eg:

Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.ReadStringVar(var aVar: TStringVar);
  2. var
  3.   sVarName: AnsiString;
  4.   tmp: array[0..255] of AnsiChar;
  5.   ads: longint;
  6. begin
  7.   if aVar.Handle = 0 then begin
  8.     sVarName := aVar.VarName;
  9.     ads := AdsSyncReadWriteReq(@AMS, ADSIGRP_SYM_HNDBYNAME, $0000, sizeof(aVar.Handle), @aVar.Handle, Length(sVarName) + 1, PChar(sVarName));
  10.   end else
  11.     ads := 0;
  12.   if ads = 0 then begin
  13.     ads := AdsSyncReadReq(@AMS, ADSIGRP_SYM_VALBYHND, aVar.Handle, Length(tmp), @tmp[0]);
  14.     if ads = 0 then aVar.Data := PlcStringToString(tmp);
  15.   end;
  16.   ShowMessage('in Procedure: ' + aVar.Data);
  17. end;

In which case, consider changing TStringVar back to using (Ansi)String instead of String[255] for its VarName field:

Code: Pascal  [Select][+][-]
  1. TStringVar = record
  2.     VarName: AnsiString;
  3.     ...
  4. end;
  5. ...
  6.  
  7. ads := AdsSyncReadWriteReq(..., Length(aVar.VarName) + 1, PAnsiChar(aVar.VarName));
« Last Edit: May 29, 2024, 07:28:58 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

 

TinyPortal © 2005-2018