Pointer Checks (POU CheckPointer)
Überwachungsfunktion CheckPointer für Zeiger
Verwenden Sie die Funktion, um den Speicherzugriff von Zeigern während der Laufzeit zu überwachen. Im Unterschied zu anderen Überwachungsfunktionen existiert für die Implementierung von CheckPointer kein standardmäßiger Vorschlag. Eine Implementierung müssen Sie selbst vornehmen!
Die Funktion CheckPointer soll überprüfen, ob der übergebene Zeiger auf eine gültige Speicheradresse verweist und ob die Ausrichtung des referenzierten Speicherbereichs zum Typ der Variablen passt, auf die der Zeiger verweist. Sind beide Bedingungen erfüllt, so wird der Zeiger selbst zurückgegeben. Andernfalls sollte die Funktion eine angemessene Fehlerbehandlung durchführen.
![]() | Deklarationsteil nicht verändern Um die Funktionalität der Überwachungsfunktionen zu erhalten, dürfen Sie den Deklarationsteil nicht verändern. Als einzige Ausnahme dürfen Sie lokale Variablen hinzufügen. |
![]() | Für den THIS-Zeiger und den SUPER-Zeiger findet kein impliziter Aufruf der Überwachungsfunktion statt. |
![]() | Die Funktion CheckPointer wirkt auch auf Variablen vom Typ REFERENCE in gleicher Weise wie auf Zeigervariablen. |
Vorlage
Deklaration:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckPointer : POINTER TO BYTE
VAR_INPUT
ptToTest : POINTER TO BYTE;
iSize : DINT;
iGran : DINT;
bWrite : BOOL;
END_VAR
Implementierung (unvollständig!):
// No standard way of implementation. Fill your own code here
{noflow}
CheckPointer := ptToTest;
{flow}
Beim Aufruf übergibt TwinCAT der Funktion folgende Eingabeparameter:
- ptToTest: Zieladresse des Zeigers
- iSize: Größe der referenzierten Variable in Bytes
- iGran: Granularität der referenzierten Größe in Bytes. Also der größte in der referenzierten Variablen enthaltene nicht-strukturierte Datentyp
- bWrite: Art des Zugriffs (TRUE=Schreibzugriff, FALSE=Lesezugriff)
Bei positivem Ergebnis der Überprüfung wird der unveränderte Eingabezeiger zurückgegeben (ptToTest).
Beispiel:
Folgendes Implementierungsbeispiel erzeugt eine Meldung im TwinCAT Ausgabefenster, sobald ein ungültiger Zeiger erkannt werden konnte. Diese Implementierung erkennt verschiedene Arten von ungültigen Zeigern. Es können aber nicht alle ungültigen Zeiger erkannt werden.
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckPointer : POINTER TO BYTE
VAR_INPUT
ptToTest : POINTER TO BYTE;
iSize : DINT;
iGran : DINT;
bWrite : BOOL;
END_VAR
IF ptToTest=0 THEN
ADSLOGSTR(ADSLOG_MSGTYPE_ERROR OR ADSLOG_MSGTYPE_STRING,'CheckPointer failed due to invalid destination address.','');
ELSIF iSize<=0 THEN
ADSLOGSTR(ADSLOG_MSGTYPE_ERROR OR ADSLOG_MSGTYPE_STRING,'CheckPointer failed due to invalid size.','');
ELSIF iGran<=0 THEN
ADSLOGSTR(ADSLOG_MSGTYPE_ERROR OR ADSLOG_MSGTYPE_STRING,'CheckPointer failed due to invalid granularity.','');
// -> Please note that the following memory area check is time consuming:
//ELSIF F_CheckMemoryArea(pData:=ptToTest,nSize:=DINT_TO_UDINT(iSize)) = E_TcMemoryArea.Unknown THEN
// ADSLOGSTR(ADSLOG_MSGTYPE_ERROR OR ADSLOG_MSGTYPE_STRING,'CheckPointer failed due to unknown memory area.','');
END_IF
CheckPointer := ptToTest;
![]() | Folge eines ungültigen Zeigers Die Folge eines ungültigen Zeigers ist in der Regel ein Stopp der Laufzeit, sobald ein beliebiger Zugriff über diesen Zeiger erfolgt. Die Funktion CheckPointer kann dies zumeist nicht verhindern. Zweck dieser Überwachungsfunktion ist vielmehr, eine effiziente Ursachendiagnose zu ermöglichen. |
Beispiel: Erzeugung eines Core Dumps zur Laufzeit in CheckBounds()
Im Folgenden finden Sie ein Beispiel, bei dem die Funktion CreateCallstackCoreDump() in der Funktion Bound Checks (POU CheckBounds) für implizite Prüfungen aufgerufen wird.
Dadurch können Sie herausfinden, in welcher Codezeile ein möglicher Zugriff außerhalb der gültigen Arraygrenzen stattfindet, ohne die Laufzeit mittels Haltepunktes anzuhalten.
Durch den Aufruf von CreateCallstackCoreDump() innerhalb der entsprechenden IF-Zweige von CheckBounds() wird die Aufrufliste (Call Stack) mit der Position des fehlerhaften Arrayzugriffs während der Laufzeit in einem Core Dump gespeichert und kann für Analysezwecke zu einem passenden Zeitpunkt geladen werden.
Funktion CheckBounds:
// Implicitly generated code : DO NOT EDIT
FUNCTION CheckBounds : DINT
VAR_INPUT
index, lower, upper: DINT;
END_VAR
// Implicitly generated code: Only an implementation suggestion
{noflow}
IF index < lower THEN
CreateCallstackCoreDump('CheckBounds_IdxTooLow');
CheckBounds := lower;
ELSIF index > upper THEN
CreateCallstackCoreDump('CheckBounds_ IdxTooHigh');
CheckBounds := upper;
ELSE
CheckBounds := index;
END_IF
Dabei wird beispielsweise ein Core Dump mit dem folgenden Namen erstellt:
Port_851_CallStackDump_CheckBounds_IdxTooLow.2322085807.core
Siehe auch: