Speicherverletzung???

Für allgemeine Fragen zur Programmierung mit PureBasic.
5mware
Beiträge: 47
Registriert: 14.12.2015 15:16

Speicherverletzung???

Beitrag von 5mware »

konzept:

die funktion erlaubt einen speicherbereich zu allokieren, in diesen speicherbereich per nummern, die zum beispiel per konstanten geregelt werden können, daten abzulegen und diese wieder bei bedarf auszulesen.

es gibt auch pendants für string und double. aber die grundfunktion ist dieser:

Code: Alles auswählen

Procedure.l object_attr( *attr, name.a, value.l = #void_number )
  Define m.l, sz.l, edit.a = #False, pos.l
  ; ***
  If value = #void_number
    If *attr
      sz = MemorySize(*attr) / 5
      ; ***
      For m = 0 To sz
        If PeekA( *attr + (5 * m) + 0 ) = name
          ProcedureReturn PeekL( *attr + (5 * m) + 1 )
          ; ***
          Break
        EndIf
      Next
    EndIf
  Else
    If *attr = 0
      *tmp = AllocateMemory( 5 ) ; 1st Byte = Name, 2nd Long = Value
      ; ***
      PokeA( *tmp + 0, name  )
      PokeL( *tmp + 1, value )
      ; ***
      ProcedureReturn *tmp
    Else
      sz = MemorySize(*attr) / 5
      ; ***
      For m = 0 To sz
        If PeekA( *attr + (5 * m) + 0 ) = name
          edit = #True
          ; ***
          pos = m
          ; ***
          Break
        EndIf
      Next
      ; ***
      Select edit
        Case #False  ; Add an new entry
          *tmp = AllocateMemory( MemorySize( *attr ) + 5 )
          ; ***
          For m = 0 To MemorySize(*attr)
            PokeA( *tmp + m, PeekA( *attr + m ) )
          Next
          ; ***
          m = MemorySize(*attr)
          ; ***
          PokeA( *tmp + m + 0, name  )
          PokeL( *tmp + m + 1, value )
        Case #True   ; Edit an existing entry
          *tmp = AllocateMemory( MemorySize( *attr ) )
          ; ***
          For m = 0 To MemorySize(*attr)
            PokeA( *tmp + m, PeekA( *attr + m ) )
          Next
          ; ***
          PokeL( *tmp + (pos * 5) + 1, value )
      EndSelect
      ; ***
      FreeMemory( *attr )
      ; ***
      ProcedureReturn *tmp
    EndIf
  EndIf
EndProcedure
Beispiel:

Code: Alles auswählen

Enumeration
#farbe
#typ
#position
EndEnumeration

*eigenschaften = object_attr( *eigenschaften, #farbe, RGB(123,88,219) )
*eigenschaften = object_attr( *eigenschaften, #typ, 20 )
*eigenschaften = object_attr( *eigenschaften, #position, 112 )

Debug object_attr( *eigenschaften, #farbe )
Debug object_attr( *eigenschaften, #typ )
Debug object_attr( *eigenschaften, #position )
Bei solchen Debug-Tests funktioniert das Ganze einwandfrei. Beim eigentlichen Projekt, das nun umfangreich ist, sind Objekte mittels Interfaces angelegt.

Der eine oder andere Objekt hat nun extra-Eigenschaften, die nun mittels dieser Lösung in die Objekt-Instanz hineingeladen werden können sollen, wenn sie benötigt werden.

Das Problem ist sowas von seltsam, das ich das gar nicht wirklich beschreiben kann. Derselbe Code läuft mal und mal nicht. Ab 4 Attributen gibt es immer Fehlermeldung, das der MemoryID nicht gültig sei. Vielleicht habe ich im Code ein fehler, aber ich kann keine entdecken. vielleicht übersehe ich was.

Ich kann mir darauf keinen Reim machen. Hat jemand eine Idee?
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7035
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Speicherverletzung???

Beitrag von STARGÅTE »

Also einen Fehler sehe ich:

Code: Alles auswählen

For m = 0 To MemorySize(*attr)
            PokeA( *tmp + m, PeekA( *attr + m ) )
          Next
Wenn der Speicher nun 5 Byte ist, dann schreibst du auch in das 5. Byte rein, was dir aber garnicht mehr reserviert wurde (geht ja nur von 0 bis 4). Hier also -1 dahinter.

Das gibt auch für deine sz = MemorySize(*attr) / 5
und For m = 0 To sz
du hast da immer ein Block zu viel.

Allerdings finde ich ein paar Sachen auch ineffizient:
  • Warum erstellt du immer wieder einen neuen Speicher und kopiert immer alles?
    Es wäre sinnvoller, immer den gleichen zu nutzen und ggf. zu Erweitern: ReAllocateMemory()
  • Code: Alles auswählen

    For m = 0 To MemorySize(*attr)-1
                PokeA( *tmp + m, PeekA( *attr + m ) )
              Next
    Sowas geht natürlich in einem Rutsch mit CopyMemory(), dann brauchst du nicht Byte für Byte kopieren
  • Wenn du das auch mit Strings machst, kannst du ja nicht mehr so einfach MemorySize(*attr) / 5 machen um zu ermittelt wie viele Einträge es gibt. Strings werden ja immer unterschiedliche Längen haben. Wie sieht denn deine String-Version aus.
  • Hast du schon mal den Purifier aktiviert, er zeigt dir ggf. auf, wo es Speicherverletzungen gibt.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
GPI
Beiträge: 1511
Registriert: 29.08.2004 13:18
Kontaktdaten:

Re: Speicherverletzung???

Beitrag von GPI »

Was man auch überdenken sollte: Sehr oft sind die Routinen schneller, wenn sie an durch 2 teilbare Grenzen abgelegt werden. Imo auch der Grund, warum wir eine 32Bit-Farbauflösung einstellen und nicht 24Bit - obwohl die Farbtiefe beides mal gleich ist (Mittlerweile nutzt man ja die überschüssigen 8Bit für den Alpha-Kanal).

Eventuell ist es auch einfach eine gute Idee, erstmal einen größeren Bereich zu reservieren (d.h. wenn man aktuell nur 10 Einträge haben würde, trotzdem für 20 Einträge reservieren). Das erspart einen viele neureserierungen und hin- und herkopieren. ReallocateMemory hat ein "Notfallprogramm". Wenn es den Speicher nicht erweitern kann, wird ein neuer angelegt und der bestehende kopiert. Kostet auch Zeit.
CodeArchiv Rebirth: Deutsches Forum Github Hilfe ist immer gern gesehen!
5mware
Beiträge: 47
Registriert: 14.12.2015 15:16

Re: Speicherverletzung???

Beitrag von 5mware »

STARGÅTE:

ok, wo du das sagst, fällt mir das jetzt auch auf.

bei der Stringfunktion wird mit derselben funktion erstmal ein pointer angelegt. dem pointer wird eine neue Speicherbereich reserviert mit der Länge des Strings (in Unicode mit Len*2, in Ascii einfach Len).

Will man den String schreiben so gillt:

create_object_attr_set_string( name, string )

Will man sie auslesen gilt:

x = create_object_attr_get_string( name )

in beiden fällen wird eigentlich object_attr genutzt über den der Pointer zum Namen ermittelt und aus dessen Speicher gelesen oder in den Geschrieben wird.

GPI:

hast recht. bei dieser funktionsgruppe ging es mir darum, das ich jetzt mittels interface verschiedene objekte für verschiedene aufgaben erstelle aber immer aus einem urobjekt ableite. die neuen objekte jedoch durchaus wiederum individuelle eigenschaften haben können und ich keine lust hatte, für jeden objekt alles neu aufzusetzen. damit die idee des urobjekts bleiben kann gibts halt in dessen memory eine extra variable *attr. die bleibt entweder nutzlos da, oder wenn objekt x nun extra eigenschaften hat, so werden diese einfach in *attr untergebracht. soviel zum konzept.


Danke an euch beiden.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7035
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Speicherverletzung???

Beitrag von STARGÅTE »

Oke, aber bei PokeS() aufpassen, dass immer noch ein NUL-Zeichen geschrieben wird.
Beim Reservieren des Speichers also StringByteLength+1 bzw +2 verwenden, oder das neue Flag: #PB_String_NoZero
Und bei Pointern aufpassen, dass sind keine LONGs, unter x64 sind es Quads, also 8 Byte.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
5mware
Beiträge: 47
Registriert: 14.12.2015 15:16

Re: Speicherverletzung???

Beitrag von 5mware »

hmm ok, danke für den tipp
5mware
Beiträge: 47
Registriert: 14.12.2015 15:16

Re: Speicherverletzung???

Beitrag von 5mware »

hab mal die funktionen nochmal überarbeitet. bevor ich das ganze jetzt mit ruhigem gewissen einsetzen kann, möchte ich mir ein letztes mal von euch einen statement abholen:

Code: Alles auswählen

#void_number = -2147483648

Procedure.l object_attr( *attr, name.a, value.l = #void_number )
  Define m.l, sz.l, edit.a = #False, pos.l, unitLen.a
  ; ***
  CompilerSelect #PB_Compiler_Unicode
    CompilerCase 1 : unitLen = 9 ; 8 Bytes für den Pointer, 1 für den Namen
    CompilerCase 0 : unitLen = 5 ; 4 Bytes für den Pointer, 1 für den Namen
  CompilerEndSelect
  ; ***
  If value = #void_number
    If *attr
      sz = MemorySize(*attr) / unitLen
      ; ***
      For m = 0 To sz - 1
        If PeekA( *attr + (unitLen * m) + 0 ) = name
          CompilerSelect #PB_Compiler_Unicode
            CompilerCase 1 : ProcedureReturn PeekQ( *attr + (unitLen * m) + 1 )
            CompilerCase 0 : ProcedureReturn PeekL( *attr + (unitLen * m) + 1 )
          CompilerEndSelect
          ; ***
          Break
        EndIf
      Next
    EndIf
  Else
    If *attr = 0
      *tmp = AllocateMemory( unitLen ) ; 1st Byte = Name, 2nd Long = Value
      ; ***
      PokeA( *tmp + 0, name  )
      ; ***
      CompilerSelect #PB_Compiler_Unicode
        CompilerCase 1 : PokeQ( *tmp + 1, value )
        CompilerCase 0 : PokeL( *tmp + 1, value )
      CompilerEndSelect
      ; ***
      ProcedureReturn *tmp
    Else
      sz = MemorySize(*attr) / unitLen
      ; ***
      If sz
        For m = 0 To sz - 1
          If PeekA( *attr + (unitLen * m) + 0 ) = name
            edit = #True
            ; ***
            pos = m
            ; ***
            Break
          EndIf
        Next
      EndIf
      ; ***
      Select edit
        Case #False  ; Add an new entry
          *tmp = AllocateMemory( MemorySize( *attr ) + unitLen )
          ; ***
          FillMemory( *tmp, MemorySize( *attr ) + unitLen, 0, #PB_Ascii )
          CopyMemory( *attr, *tmp, MemorySize(*attr) )
          ; ***
          m = MemorySize(*attr)
          ; ***
          PokeA( *tmp + m + 0, name  )
          ; ***
          CompilerSelect #PB_Compiler_Unicode
            CompilerCase 1 : PokeQ( *tmp + m + 1, value )
            CompilerCase 0 : PokeL( *tmp + m + 1, value )
          CompilerEndSelect
        Case #True   ; Edit an existing entry
          *tmp = AllocateMemory( MemorySize( *attr ) )
          ; ***
          FillMemory( *tmp, MemorySize( *attr ), 0, #PB_Ascii )
          CopyMemory( *attr, *tmp, MemorySize(*attr) )
          ; ***
          CompilerSelect #PB_Compiler_Unicode
            CompilerCase 1 : PokeQ( *tmp + (pos * unitLen) + 1, value )
            CompilerCase 0 : PokeL( *tmp + (pos * unitLen) + 1, value )
          CompilerEndSelect
      EndSelect
      ; ***
      FreeMemory( *attr )
      ; ***
      ProcedureReturn *tmp
    EndIf
  EndIf
EndProcedure

Procedure.l object_attr_set_string( *attr, name.a, value.s )
  Define m, sz, *ptr = 0, unitLen.a
  ; ***
  CompilerSelect #PB_Compiler_Unicode
    CompilerCase 1 : unitLen = 9 ; 8 Bytes für den Pointer, 1 für den Namen
    CompilerCase 0 : unitLen = 5 ; 4 Bytes für den Pointer, 1 für den Namen
  CompilerEndSelect
  ; ***
  If *attr
    sz = MemorySize(*attr) / unitLen
    ; ***
    For m = 0 To sz - 1
      If PeekA( *attr + (unitLen * m) + 0 ) = name
        CompilerSelect #PB_Compiler_Unicode
          CompilerCase 1 : *ptr = PeekQ( *attr + (unitLen * m) + 1 )
          CompilerCase 0 : *ptr = PeekL( *attr + (unitLen * m) + 1 )
        CompilerEndSelect
        ; ***
        Break
      EndIf
    Next
    ; ***
    If *ptr
      FreeMemory(*ptr)
    EndIf
    ; ***
    CompilerSelect #PB_Compiler_Unicode
      CompilerCase 1
        *ptr = AllocateMemory( (Len(value) * 2) + 2 )
        ; ***
        PokeS( *ptr, value, (Len(value) * 2) + 2, #PB_Unicode )
      CompilerCase 0
        *ptr = AllocateMemory( Len(value) + 1 )
        ; ***
        PokeS( *ptr, value, Len(value) + 1, #PB_Ascii )
    CompilerEndSelect
    ; ***
    ProcedureReturn object_attr( *attr, name, *ptr )
  EndIf
EndProcedure

Procedure.s object_attr_get_string( *attr, name.a )
  Define m, sz, *ptr = 0, unitLen.a
  ; ***
  CompilerSelect #PB_Compiler_Unicode
    CompilerCase 1 : unitLen = 9 ; 8 Bytes für den Pointer, 1 für den Namen
    CompilerCase 0 : unitLen = 5 ; 4 Bytes für den Pointer, 1 für den Namen
  CompilerEndSelect
  ; ***
  If *attr
    sz = MemorySize(*attr) / unitLen
    ; ***
    For m = 0 To sz - 1
      If PeekA( *attr + (unitLen * m) + 0 ) = name
        CompilerSelect #PB_Compiler_Unicode
          CompilerCase 1 : *ptr = PeekQ( *attr + (unitLen * m) + 1 )
          CompilerCase 0 : *ptr = PeekL( *attr + (unitLen * m) + 1 )
        CompilerEndSelect
        ; ***
        Break
      EndIf
    Next
    ; ***
    If *ptr
      CompilerSelect #PB_Compiler_Unicode
        CompilerCase 1
          ProcedureReturn PeekS( *ptr, MemorySize(*ptr) / 2, #PB_Unicode )
        CompilerCase 0
          ProcedureReturn PeekS( *ptr, MemorySize(*ptr), #PB_Ascii )
      CompilerEndSelect
    EndIf
  EndIf
EndProcedure

Procedure.l object_attr_set_double( *attr, name.a, value.d )
  Define m, sz, *ptr = 0, unitLen.a
  ; ***
  CompilerSelect #PB_Compiler_Unicode
    CompilerCase 1 : unitLen = 9 ; 8 Bytes für den Pointer, 1 für den Namen
    CompilerCase 0 : unitLen = 5 ; 4 Bytes für den Pointer, 1 für den Namen
  CompilerEndSelect
  ; ***
  If *attr
    sz = MemorySize(*attr) / unitLen
    ; ***
    For m = 0 To sz - 1
      If PeekA( *attr + (unitLen * m) + 0 ) = name
        CompilerSelect #PB_Compiler_Unicode
          CompilerCase 1 : *ptr = PeekQ( *attr + (unitLen * m) + 1 )
          CompilerCase 0 : *ptr = PeekL( *attr + (unitLen * m) + 1 )
        CompilerEndSelect
        ; ***
        Break
      EndIf
    Next
    ; ***
    If *ptr
      FreeMemory(*ptr)
    EndIf
    ; ***
    *ptr = AllocateMemory( 8 )
    ; ***
    PokeD( *ptr, value )
    ; ***
    ProcedureReturn object_attr( *attr, name, *ptr )
  EndIf
EndProcedure

Procedure.d object_attr_get_double( *attr, name.a )
  Define m, sz, *ptr = 0, unitLen.a
  ; ***
  CompilerSelect #PB_Compiler_Unicode
    CompilerCase 1 : unitLen = 9 ; 8 Bytes für den Pointer, 1 für den Namen
    CompilerCase 0 : unitLen = 5 ; 4 Bytes für den Pointer, 1 für den Namen
  CompilerEndSelect
  ; ***
  If *attr
    sz = MemorySize(*attr) / unitLen
    ; ***
    For m = 0 To sz - 1
      If PeekA( *attr + (unitLen * m) + 0 ) = name
        CompilerSelect #PB_Compiler_Unicode
          CompilerCase 1 : *ptr = PeekQ( *attr + (unitLen * m) + 1 )
          CompilerCase 0 : *ptr = PeekL( *attr + (unitLen * m) + 1 )
        CompilerEndSelect
        ; ***
        Break
      EndIf
    Next
    ; ***
    If *ptr
      ProcedureReturn PeekD( *ptr )
    EndIf
  EndIf
EndProcedure
Beispiele:

Code: Alles auswählen

Enumeration
#farbe
#typ
#position
#adresse
#string1
#string2
#kommaz
#plz
#ort
EndEnumeration

*eigenschaften = object_attr( *eigenschaften, #farbe, 345 )
*eigenschaften = object_attr( *eigenschaften, #typ, 20 )
*eigenschaften = object_attr( *eigenschaften, #position, 112 )
*eigenschaften = object_attr_set_double( *eigenschaften, #kommaz, 3078.94 )
*eigenschaften = object_attr_set_string( *eigenschaften, #string1, "Hallo Welt" )
*eigenschaften = object_attr_set_string( *eigenschaften, #string2, "Alles in Ordnung :-)" )
*eigenschaften = object_attr( *eigenschaften, #adresse, 80 )
*eigenschaften = object_attr( *eigenschaften, #plz, 99 )
*eigenschaften = object_attr( *eigenschaften, #ort, 174 )

Debug object_attr( *eigenschaften, #farbe )
Debug object_attr( *eigenschaften, #typ )
Debug object_attr( *eigenschaften, #position )
Debug object_attr( *eigenschaften, #adresse )
Debug object_attr( *eigenschaften, #plz )
Debug object_attr( *eigenschaften, #ort )

Debug ""

Debug object_attr( *eigenschaften, #plz )
Debug object_attr( *eigenschaften, #farbe )
Debug object_attr( *eigenschaften, #ort )
Debug object_attr( *eigenschaften, #typ )
Debug object_attr( *eigenschaften, #adresse )
Debug object_attr( *eigenschaften, #position )

Debug ""
*eigenschaften = object_attr( *eigenschaften, #position, 100 )
Debug object_attr( *eigenschaften, #position )

Debug ""
*eigenschaften = object_attr( *eigenschaften, #position, 150 )
Debug object_attr( *eigenschaften, #position )

Debug ""
*eigenschaften = object_attr( *eigenschaften, #position, 200 )
Debug object_attr( *eigenschaften, #position )

Debug ""
*eigenschaften = object_attr( *eigenschaften, #position, 250 )
Debug object_attr( *eigenschaften, #position )

Debug ""
Debug StrD(object_attr_get_double( *eigenschaften, #kommaz ), 2)

Debug ""
Debug object_attr_get_string( *eigenschaften, #string1 )
Debug object_attr_get_string( *eigenschaften, #string2 )

Debug ""
Antworten