AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein [AV] Ende einer Prozedur verursacht eine AV...
Thema durchsuchen
Ansicht
Themen-Optionen

[AV] Ende einer Prozedur verursacht eine AV...

Ein Thema von Daniel G · begonnen am 11. Jul 2006 · letzter Beitrag vom 12. Jul 2006
Antwort Antwort
Daniel G
(Gast)

n/a Beiträge
 
#1

[AV] Ende einer Prozedur verursacht eine AV...

  Alt 11. Jul 2006, 22:53
N'Abend,

Ich hab' mal wieder ein kleines Problem mit einem C - Code, den ich nach Delphi portiert habe. (Ja, ich weiß, ich sollte diese verdammte Sprache endlich lernen ). Da in dem Original die AV nicht auftritt, denke ich, dass das mit meiner Portierung zu tun hat...

Nevertheless, mein Problem liegt hier:

Delphi-Quellcode:
//----------------------------------------------------------------------------
// ATA-Befehle unter Windows 2000 oder XP versenden
Function TAAMClass.SendCommand_Win2000(pATARegs: PATARegs; var pBuf;
BufSize: Cardinal; pResultSize: Cardinal): Boolean;
var
  Size: Cardinal;
  VirtualAddress: Pointer;
  pAPT: ATA_PASS_THROUGH;
  BytesReturned: LongWord;
  Status: Boolean;
  ReturnedSize: Cardinal;
begin
  Result := FALSE;
  BytesReturned := 0;

  Size := sizeof(ATA_PASS_THROUGH) + BufSize;
  // Datenpuffer mit VirtualAlloc anfordern, damit der Gerätetreiber den Speicher ansprechen kann
  VirtualAddress := VirtualAlloc(NIL, Size, MEM_COMMIT, PAGE_READWRITE);
  pAPT := ATA_PASS_THROUGH(VirtualAddress^);

  if Assigned(@pAPT) then
  begin
      //ZeroMemory(@pAPT, Size);
      // Größe des Datenpuffers setzen
      pAPT.DataBufferSize := BufSize;
      // ATA-Register setzen
      pAPT.IdeReg.bFeaturesReg := pATARegs^.Reg[0];
      pAPT.IdeReg.bSectorCountReg := pATARegs^.Reg[1];
      pAPT.IdeReg.bSectorNumberReg := pATARegs^.Reg[2];
      pAPT.IdeReg.bCylLowReg := pATARegs^.Reg[3];
      pAPT.IdeReg.bCylHighReg := pATARegs^.Reg[4];
      pAPT.IdeReg.bDriveHeadReg := pATARegs^.Reg[5];
      pAPT.IdeReg.bCommandReg := pATARegs^.Reg[6];

      if (pAPT.IdeReg.bCommandReg = $EC) then // ist es ATA IDENTIFY?
      begin
           // Windows XP merkt sich den IDE-Konfigurationssektor
          // daher vorher mit IOCTL_SCSI_RESCAN_BUS für ungültig erklären

          DeviceIoControl(fDriveHandle, IOCTL_SCSI_RESCAN_BUS, NIL, 0, NIL, 0, BytesReturned, 0);
          // eine halbe Sekunde warten
          Sleep(500);
      end;

      BytesReturned := 0;
      
      Status := DeviceIoControl(fDriveHandle, IOCTL_IDE_PASS_THROUGH,
                                    @pAPT, Size, @pAPT, Size, BytesReturned, 0);
      if not Status then
        fError := aec_CommandFailed
      else
      begin
          if Assigned(@pBuf) then
          begin
              if (BufSize <> 0) then
                ZeroMemory(@pBuf, BufSize);
              if (BytesReturned > sizeof(ATA_PASS_THROUGH)) then
              begin
                  ReturnedSize := BytesReturned - sizeof(ATA_PASS_THROUGH);
                  if (pResultSize <> 0) then
                    pResultSize := ReturnedSize;
                  if (ReturnedSize > BufSize) then
                    ReturnedSize := BufSize;
                  Move(pAPT.DataBuffer, pBuf, ReturnedSize);
              end;
          end;
          Result := TRUE;
      end;
      VirtualFree(@pAPT, Size, MEM_RELEASE);
  end
  else
    fError := aec_OutOfMemory;
end;
Nachdem die Funktion durchlaufen wurde, werde ich mit einer AV bombadiert:

Zitat:
---------------------------
Anwendungsfehler
---------------------------
Exception EAccessViolation in Modul bquiet.exe bei 57201020.

Zugriffsverletzung bei Adresse 57202020. Lesen von Adresse 57202020.


---------------------------
OK
---------------------------
Ich tippe mal, ich mache dort irgendwie Mist mit den Pointern. Leider kann ich mit dieser Meldung absolut nichts anfangen, da im Vergleich zu sonst dort ausnahmsweise ne Adress steht und nicht, wie gewohnt, 00000000 ()

Der äquivalente C - Code wäre:

Code:
//----------------------------------------------------------------------------
// ATA-Befehle unter Windows 2000 oder XP versenden

BOOL CWinAta::SendCommand_Win2000(PATARegs pATARegs, void *pBuf, unsigned int BufSize, unsigned int *pResultSize)
{
 
  //---------------------------------------------------
  // Definitionen und Datenstruktur für Windows 2000 und XP
  // aus dem DDK-Headerfile ntddscsi.h übernommen
 
  #define IOCTL_IDE_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x040A, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
  #define FILE_ANY_ACCESS        0
  #define IOCTL_SCSI_RESCAN_BUS  CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)

  typedef struct
  {
      IDEREGS IdeReg;
      ULONG  DataBufferSize;
      UCHAR  DataBuffer[1];
  } ATA_PASS_THROUGH;
  //---------------------------------------------------
 
 
  BOOL Result = FALSE;
 
  unsigned int Size = sizeof(ATA_PASS_THROUGH) + BufSize;
  // Datenpuffer mit VirtualAlloc anfordern, damit der Gerätetreiber den Speicher ansprechen kann
  ATA_PASS_THROUGH *pAPT = (ATA_PASS_THROUGH *)VirtualAlloc(NULL, Size, MEM_COMMIT, PAGE_READWRITE);
 
  if (pAPT)
  {
      memset(pAPT, 0, Size);
      // Größe des Datenpuffers setzen
      pAPT->DataBufferSize         = BufSize;
      // ATA-Register setzen
      pAPT->IdeReg.bFeaturesReg    = pATARegs->Reg[0];
      pAPT->IdeReg.bSectorCountReg = pATARegs->Reg[1];
      pAPT->IdeReg.bSectorNumberReg = pATARegs->Reg[2];
      pAPT->IdeReg.bCylLowReg      = pATARegs->Reg[3];
      pAPT->IdeReg.bCylHighReg     = pATARegs->Reg[4];
      pAPT->IdeReg.bDriveHeadReg   = pATARegs->Reg[5];
      pAPT->IdeReg.bCommandReg     = pATARegs->Reg[6];

      if (pAPT->IdeReg.bCommandReg == 0xEC) // ist es ATA IDENTIFY?
      {
     // Windows XP merkt sich den IDE-Konfigurationssektor
          // daher vorher mit IOCTL_SCSI_RESCAN_BUS für ungültig erklären
          DWORD BytesReturned = 0;
          (void)DeviceIoControl(Device, IOCTL_SCSI_RESCAN_BUS, NULL, 0, NULL, 0, &BytesReturned, FALSE);
          // eine halbe Sekunde warten
          Sleep(500);  
      }

      DWORD BytesReturned = 0;
     
      BOOL Status = DeviceIoControl(Device, IOCTL_IDE_PASS_THROUGH,
                                    pAPT, Size, pAPT, Size, &BytesReturned, FALSE);
      if (!Status)
        WinAtaErrorCode = aec_CommandFailed;
      else
      {
          if (pBuf)
          {
              if (BufSize)
                memset(pBuf, 0, BufSize);
              if (BytesReturned > sizeof(ATA_PASS_THROUGH))
              {
                  unsigned int ReturnedSize = BytesReturned - sizeof(ATA_PASS_THROUGH);
                  if (pResultSize)
                    *pResultSize = ReturnedSize;
                  if (ReturnedSize > BufSize)
                    ReturnedSize = BufSize;
                   
                  memcpy(pBuf, pAPT->DataBuffer, ReturnedSize);
              }
          }
          Result = TRUE;
      }
      VirtualFree(pAPT, Size, MEM_RELEASE);
  }
  else
    WinAtaErrorCode = aec_OutOfMemory;
 
  return Result;
}
Hat irgendwer eine Idee? Im Anhang ist mal das komplette Delphi - Projekt. Auf das C - Original verlinke ich lieber. Ist von der c't... es handelt sich um die "WinATA.cpp".

Download vpn Heise *klick*

Danke schonmal für's lesen.
Angehängte Dateien
Dateityp: zip bequiet_177.zip (8,4 KB, 1x aufgerufen)
  Mit Zitat antworten Zitat
Daniel G
(Gast)

n/a Beiträge
 
#2

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 10:56
So, ich bins wieder. Ich habe mir das CPU - Fenster mal genauer angesehen. Es hängt also wirklich mit irgendeinem falsch zeigenden Pointer zusammen. So sehen ich in dem Fenster, wo die ganzen Adressen stehen, lauter Fragezeichen.

Kann es eventuell an einer falschen Verwendung von VirtualAlloc liegen?
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#3

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 13:02
Oder an MemSet() und MemCopy()?. Wie wärs denn mit was debugbarem, wenn du es nicht hinbekommst die Adressen zu debuggen...
  Mit Zitat antworten Zitat
Daniel G
(Gast)

n/a Beiträge
 
#4

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 13:04
Zitat von Muetze1:
Wie wärs denn mit was debugbarem, wenn du es nicht hinbekommst die Adressen zu debuggen...
Ich weiß, du willst mir damit was sagen, nur was?

//Edit:
Ich bin gerade auf die großartige Idee gekommen, dass ich die MadExcept ja wieder installieren könnte. Ich hol das mal eben nach...

//Edit2: So, hier mal der Bugreport. Das Projekt selbst befindet sich ja oben im Anhang
Angehängte Dateien
Dateityp: txt bugreport_786.txt (8,8 KB, 8x aufgerufen)
  Mit Zitat antworten Zitat
Daniel G
(Gast)

n/a Beiträge
 
#5

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 13:43
Zitat von Muetze1:
Oder an MemSet() und MemCopy()?.
Ich hatte für MemSet ZeroMemory benutzt, da MemSet lauter nullen setzt. Also dachte ich, ZeroMemory würde dasselbe machen. Oder ist das ein Irrglaube? Ich hatte den Befehl ja auskommentiert. Wenn ich ihn wieder hinnein nehme, zeigt der Pointer ins Leere...
  Mit Zitat antworten Zitat
Benutzerbild von Flocke
Flocke

Registriert seit: 9. Jun 2005
Ort: Unna
1.172 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 15:46
Code:
ATA_PASS_THROUGH *pAPT
Das bedeutet, dass pAPT ein ZEIGER auf eine ATA_PASS_THROUGH-Struktur ist.

Nachdem du das in Delphi geändert hast, kannst du den Typecast und die @'s vor pAPT entfernen (Assigned(@x) ist 'ne ziemlich sinnlose Abfrage).
Volker
Besucht meine Garage
Aktuell: RtfLabel 1.3d, PrintToFile 1.4
  Mit Zitat antworten Zitat
Daniel G
(Gast)

n/a Beiträge
 
#7

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 17:09
Hi Flocke,

das heißt also, wenn ich
Delphi-Quellcode:
Type
PATA_PASS_THROUGH = ^ATA_PASS_THROUGH
definieren würde, könnte ich das so schreiben:
Delphi-Quellcode:
var
pAPT: PATA_PASS_THROUGH;
begin
pAPT := VirtualAlloc(NIL, Size, MEM_COMMIT, PAGE_READWRITE);
if Assigned(pAPT) then
[...]
Damit wäre ich diese AV schonmal interessanterweise los. Vllt. is' das ja doch nicht so kompliziert, wie ich denke... Aber warum ist "Assigned(@pAPT)" mit der alten Definition denn sinnlos?
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.105 Beiträge
 
Delphi 11 Alexandria
 
#8

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 18:18
Moin Daniel,

Zitat von Daniel G:
Aber warum ist "Assigned(@pAPT)" mit der alten Definition denn sinnlos?
das hat nichts mit der alten Definition zu tun.

Assigned prüft den Ausdruck auf nil. Nun wird die Adresse einer Variablen aber wohl nie gleich nil sein...
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Daniel G
(Gast)

n/a Beiträge
 
#9

Re: [AV] Ende einer Prozedur verursacht eine AV...

  Alt 12. Jul 2006, 19:06
Zitat von Christian Seehase:
Nun wird die Adresse einer Variablen aber wohl nie gleich nil sein...
Ähä.. Ok, das ergibt Sinn....
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz