• Bitte schaltet eure Ad Blocker aus. SLinfo kann nur betrieben werden, wenn es durch Werbung Einnahmen erzielt. Vielen Dank!!
  • Wir freuen uns, wenn du dich in unserem Forum anmeldest. Bitte beachte, dass die Freigabe per Hand durchgeführt wird (Schutz vor Spammer). Damit kann die Freigabe bis zu 24 Stunden dauern.
  • Wir verwenden Cookies, um Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf unsere Website zu analysieren. Sie geben Einwilligung zu unseren Cookies, wenn Sie unsere Webseite weiterhin nutzen.

"Seiteneffekte" bei String-Speicherverwaltung bekannt ?

argus Portal

Freund/in des Forums
Hallo, tut mir leid für eine etwas unscharfe Frage ;-)

Ich habe ein Problem mit einem Script, das ich nur
grob umschreiben kann und wo es bei Antworten im Grunde
nur um Erfahrungswerte gehen kann. Den Quellcode kann ich
hier nicht zeigen, da er zu komplex ist und ausserdem
Teil eines Projektes ist, der nicht unbedingt öffentlich
sein muss ;-)

Ich arbeite mit Strings. Einige sind global angelegt,
andere lokal in diversen Funktionen. Ich rufe in Funktionen
weitere Funktionen auf, wobei ich die lokalen Strings als
Zwischenresultate in Form der Rückgabewerte weiterreiche.

Bearbeitet werden die Strings mit llGetSubString,
llDeleteSubString und llInsertString. Das Schema
einer "Verarbeitungskette" ist immer dasselbe. Aber
zuverlässig läuft es nur das erste Mal
. Danach wird
es unzuverlässig. Es scheint, das bestimmte Daten
nicht mehr richtig gelesen werden. Es ist zu "99%iger"
Sicherheit kein Programmierfehler.


Meine Frage: Ist jemandem schon einmal ein unerklärliches
Verhalten eines Scriptes aufgefallen, das eigentlich nur
an fehlerhafter Speicherverwaltung in LSL liegen kann?

Das also LSL z.B. lokale und globale Strings, wenn sie wie
im vorliegenden Fall ziemlich oft hin und hergeschoben werden,
verfremdet?


Mit diversen Debugausgaben habe ich Stringlängen und
Zwischenresultate geprüft. Ich kann keinen Fehler finden.
Bevor ich aufwändigere Prüfungen vornehme, frage ich lieber
erstmal hier und spare evtl. Zeit und muss evtl. einen anderen
Weg gehen.
 
Also, wenn ich mir manchmal gewisse Fehler nicht auf Anhieb erklaeren kann, setze ich einfach an jede relevante Stelle, wo die Daten aufgerufen/verarbeitet werden ein llSay rein. Natuerlich nummeriere ich die Ausgaben, damit ich gleich weiss an welcher Stelle etwas falsch laeuft.
Es sieht dann folgendermassen aus: llSay(0,"test1 " + (string)variable);

Das hat mir schon oft weiter geholfen.

LG
Dae
 
So gehe ich auch vor. Das meinte ich mit "Debugausgaben". Wenn es zu dem Problem kommt,
werden Daten offenbar temporär "verfälscht" und sehen nachher aber normal aus.

So seltsam das klingt, so ist es auch. Ich kämpfe damit jetzt ein paar Tage und bin ziemlich
ratlos. Daher ja auch die Idee, das hier intern (Compilermässig) etwas schief läuft.
 
Eine Fehlerquelle die mir jetzt spontan einfallen wuerde, waere die Kombination integer/float.

Was natuerlich auch sein kann...
llGetPrimitiveparams([ PRIM_TEXTURE, integer face ] ... ist nicht gleich llGetTextureOffset

...eventuell bekommst du beim Temporaeren Wert je nach abfrage andere Werte.
Bei dem Textur Offset zum Beispiel erhaelt man fuer den Offset unterschiedliche viele Nachkommastellen. Wenn man die dann als string behandelt und lediglich mit llGetSubString aufteilt, kommen total falsche Werte raus.

LG
Dae
 
Zuletzt bearbeitet:
Ich bringe in den Strings Integerwerte unter. Es gibt kein Casting auf Float. Ich arbeite mit festen Offsets,
wobei ich je nach Situation Teile ersetze (durch Delete und anschliessendem Insert). Dann scanne ich
globale Strings, die plötzlich falsche Werte zu enthalten scheinen. Sehe ich nach dem Zugriff aber
nach, sieht alles aus, wie es sein soll.

Über den Wolken schaut mir einer zu und lacht sich tot.
 
Zuletzt bearbeitet:
Also arbeitest du tatsaechlich mit Offsets?
An Textur Offsets habe ich mir anfangs auch die Zaehne ausgebissen, das ist echt ne Harte Nuss.
Du musst unbedingt drauf achten, das deine Temporaeren Werte im absolut selben Format wie die fixen Werte abgefragt werden, andernfalls funktioniert es nicht.
Probiere aus mit welcher der Methoden du einheitliche Werte bekommst und nutze die.

Darum habe ich oben die beiden Befehle aufgefuehrt, denn...
<1.0000, 1.0000, 0.0000> != <1.00000, 1.00000, 0.00000>
...ganz besonders als String nicht.

LG
Dae
 
Zuletzt bearbeitet:
Es geht hier um Koordinatenpaare. Drei zu je zwei Byte (Zeichen) in einer Kette. Also muss ich
die Offsets nicht beobachten. Sie liegen immer genau 6 Zeichen auseinander.

Einer der globalen Strings dient mir als interner Speicher. Und nur damit arbeite ich.
Die Daten kommen und gehen berechnungsmässig nur in/aus diesem Speicher.
Prims werden dann erst durch das Resultat beeinflusst. Die "Aussenwelt" kann
darum bei der Problemsuche ignoriert werden.

Zusatzinfo: Von einem vollen Speicher bin ich weit entfernt. Daran liegt es nicht.


Das Konzept funktioniert ja auch. IMMER beim ersten und zweiten Mal. Ab dann kommt
der Zufall ins Spiel.
 
Manchmal, aber nicht immer, kann es vom Nutzen sein, die Variablen direkt im Befehl selber berechnen zu lassen.
Wesentlich stabiler dagegen sind vorberechnete Variablen direkt ueber dem eigentlichen Befehl.

Also statt im Befehl a + b, direkt ueber dem Befehl variable a + b berechnen und erst dann das Ergebnis im Befehl ausfuehren.
 
Es geht hier um Koordinatenpaare. Drei zu je zwei Byte (Zeichen) in einer Kette. Also muss ich
die Offsets nicht beobachten. Sie liegen immer genau 6 Zeichen auseinander.

Einer der globalen Strings dient mir als interner Speicher. Und nur damit arbeite ich.
Die Daten kommen und gehen berechnungsmässig nur in/aus diesem Speicher.
Prims werden dann erst durch das Resultat beeinflusst. Die "Aussenwelt" kann
darum bei der Problemsuche ignoriert werden.

Zusatzinfo: Von einem vollen Speicher bin ich weit entfernt. Daran liegt es nicht.


Das Konzept funktioniert ja auch. IMMER beim ersten und zweiten Mal. Ab dann kommt
der Zufall ins Spiel.

Schreib doch mal Beispielcode mit dem man das hier reproduzieren kann.

Aber typecasting string --> float -- > string usw. kann leider wirklich oft ein kleines Problem sein. Das Problem hier ist, dass es da bei den Nachkommazahlen probleme geben kann.
Strings, die etwa mit (string) 1.1234567890123 erzeugt werden, sind leider nur auf 6 Nachkommazahlen begrenzt. Während floats in LSL auf bis zu 9 Nachkommazahlen genau sind (32bit float nach IEEE754).
Ansonsten sollten bei llGetSubString oder llInsertString eigentlich keine Verfälschungen auftreten. Probleme dort gibt es vor allem dann, wenn da ein paar Parameter nicht wirklich passen, z.B. Start- und Endpunkt des Substrings.

Dass da der Compiler Fehler macht und z.B. die Strings irgendwie im Speicher falsch verkettet (Zeiger falsch setzt oder so) glaube ich eher weniger. Normal müsste da dann das Programm abschmieren...aber man weiß ja nie. Deswegen der Beispielcode, damit man das irgendwie genauer Eingrenzen kann.
 
Manchmal, aber nicht immer, kann es vom Nutzen sein, die Variablen direkt im Befehl selber berechnen zu lassen.
Wesentlich stabiler dagegen sind vorberechnete Variablen direkt ueber dem eigentlichen Befehl.

Also statt im Befehl a + b, direkt ueber dem Befehl variable a + b berechnen und erst dann das Ergebnis im Befehl ausfuehren.

Das macht vermutlich keinen Unterschied, da die Scripte ja nicht wie in Basic schritt für Schritt abgearbeitet werden, die werden kompiliert und dann erst ausgeführt.

Aus
Code:
a = b +c;
funktion (a);

sollte der Compiler beim kompilieren des Scripts dabei letztendlich den selben CIL-Code/Bytecode machen wie aus

Code:
function(b+c);

D.h. der Kompiler schaut sich die Zusammenhänge, die Klammern usw. vermutlich schon genauer an. Und wirft dabei möglicherweise auch unnötig belegte Variablen ganz raus, je nach dem wie gut er den Code optimiert.
 
@ Shirley

Normalerweise ist es auch gar kein Problem, direkt im Befehl berechnen zu lassen. Es gibt aber Kombinationen die tatsaechlich im Befehl zu fehlerhaften Werten fuehren und man quasi dazu gezwungen ist, die Variablen vorher ueber dem eigentlichen Befehl zu verarbeiten. Frag mich jetzt nicht welche das sind, aber ich habe mich echt schon das ein oder andere mal geaergert, weil ich das Script diesbezueglich aendern musste.

LG
Dae
 
Bearbeitet werden die Strings mit llGetSubString,
llDeleteSubString und llInsertString. Das Schema
einer "Verarbeitungskette" ist immer dasselbe. Aber
zuverlässig läuft es nur das erste Mal
. Danach wird
es unzuverlässig. Es scheint, das bestimmte Daten
nicht mehr richtig gelesen werden. Es ist zu "99%iger"
Sicherheit kein Programmierfehler.

Also du speicherst zwei Integerwerte zu Strings gecasted in einer globalen Variablen.
Was machst du, wenn einer der Werte weniger Stellen hat, füllst du die Stellen dann mit "0" auf?

Es ist zu 99%-iger Sicherheit kein Fehler von LSL.

Kannst du ein kleines Beispielskript erzeugen, wo der Fehler vorkommt, und bei dem alles andere von deinem Projekt rausgelöscht ist?
Dann kann man sich das genauer ansehen. Ansonsten ist hier alles reine Spekulation.

Ich teste bei solchen Fehlern alle Stellen an denen ich Stringfunktionen verwende in einem neuen, leeren Skript jeweils einzeln (z.B. so: string t = "test"; llOwnerSay(llGetSubString(t, 0, llSubStringIndex(t, "e"))); ), und schaue mir vor allem genau an, ob ich die Indexe richtig benutze. Indexe sind eine sehr häufige Fehlerquelle bei Stringfunktionen ("schneide alles bis zum Komma aus", "die ersten fünf Zeichen", etc.).


Ich teste fast immer alle etwas komplizierteren Programmteile mit Stringfunktionen einzeln, in einem leeren Skript, und das obwohl ich mit dem Krams schon 20 Jahre Erfahrung habe.
Einfach weil man bei den Indexen viel zu leicht mal etwas verhaut und übersieht.

(Bei größeren Programme arbeite ich mittlerweile sogar bei Funktionen und Klassen test-driven, also ich entwickle eine Testfunktion wo ich verschiedene Eingabewerte mit den zu erwartenden Ausgabewerten der neuen Funktionen/Klassen vergleiche, bevor ich den eigentlichen Programmcode entwickle)
 
Zuletzt bearbeitet:
Also du speicherst zwei Integerwerte zu Strings gecasted in einer globalen Variablen.
Was machst du, wenn einer der Werte weniger Stellen hat, füllst du die Stellen dann mit "0" auf?

Nicht nötig. Ich schrieb ja schon, das die Offsets (Indizes) immer gleich weit auseinander sind. Format: x1y1x2y2x3y3

Das ganze deckt eine Matrix von 7*7 ab. Ein Koordinatenpaar ist daher immer 2-stellig (1 x und 1 y)

Es ist zu 99%-iger Sicherheit kein Fehler von LSL.

Ein virtueller Kasten Bier. Meine 99% gegen deine 99% ;-)


Kannst du ein kleines Beispielskript erzeugen, wo der Fehler vorkommt, und bei dem alles andere von deinem Projekt rausgelöscht ist?
Dann kann man sich das genauer ansehen. Ansonsten ist hier alles reine Spekulation.

Wenn mir nichts weiter mehr einfällt, muss ich daraus ohnehin eine Art Testscript bauen. Eine allgemeine unabhängige Version
poste ich dann hier.

Im Grunde habe ich aber schon eine wichtige Antwort: Bis auf Daes Hinweis, auch schon seltsames Verhalten beobachtet zu haben,
scheinen hier keine diesbzgl. Erfahrungen gemacht worden zu sein. Entweder, ich sehe den Wald vor Bäumen nicht und habe wirklich
einen hinterhältigen Fehler eingebaut, bzw. etwas übersehen, oder ich habe eben wirklich dem Compiler durch ein "ungünstiges" Konstrukt
ein Bein gestellt.
 
Weisst du was auch ein geiler Fehler ist? :D
Code:
if(a == b);
{
   llSay(0,"test");
}

Du glaubst nicht wie viele Stunden ich wegen diesem beknackten Fluechtigkeits-Fehler schon suchen durfte.
Das Script wird nicht angehalten, es kommt kein Syntax Error und keine Meldung im Debug Channel.
Das Script laeuft, lediglich die eine Abfrage funktioniert nur nicht.

LG
Dae
 
Ganz selten kommt es mal vor das ein Prim "kaput" ist. Dann laufen die Scripte da nicht richtig. Also mal
den Prim austauschen. Falls es das nicht war würde ich drauf wetten das der Fehler in deinen Code versteckt
ist.

Es gibt zwei Sorten von Programmen:
Die einen sind so klein das offensichtlich keine Fehler enthalten.
Die anderen sind so groß das sie keine offensichtlichen Fehler enthalten.

bis denne
Jan
 
Ganz selten kommt es mal vor das ein Prim "kaput" ist. Dann laufen die Scripte da nicht richtig.

Hatte ich auch schon ...

Also mal
den Prim austauschen. Falls es das nicht war würde ich drauf wetten das der Fehler in deinen Code versteckt
ist.

Es gibt zwei Sorten von Programmen:
Die einen sind so klein das offensichtlich keine Fehler enthalten.
Die anderen sind so groß das sie keine offensichtlichen Fehler enthalten.

bis denne
Jan


So einfach ist es nicht. Es gibt mindestens eine weitere Kategorie (die du ja selbst schon nanntest..):
Wenn ein Programm einen Fehler seiner Umgebung triggert. Ob das der Compiler, das Betriebssystem
oder was auch immer ist.

Google einmal beispielsweise nach "Compilerbugs".

Völlig unabhängig davon, wie es sich mit meinem konkreten Problem jetzt verhält, ist es wenig sinnvoll
(und praxisfremd), diese dritte Möglichkeit aus lauter Demut auszuschliessen.
 
Ich werde, sobald ich Zeit habe, die verdächtigen Funktionen extrahieren. Evtl. lichtet sich der
Wald dann und ich erhalte Gewissheit.
 
Weisst du was auch ein geiler Fehler ist? :D
Code:
if(a == b);
{
   llSay(0,"test");
}


Ja. Sowas treibt einen in den Wahnsinn. Weil man diese Stellen bei der Fehlersuche ausschliesst, weil es
"dort so simpel ist".

Deshalb habe ich mir Copy&Paste abgewöhnt. Man macht eine Zuweisung und will später abfragen und kopiert
die Zeile und fügt sie wieder ein, ohne den Operator anzupassen ...

Ich sage nur "goto fail". Solche Stellen sehen so unverdächtig aus, das man manchmal sogar Vorsatz vermutet :)
 
Ich meide Listen bei jedem Projekt, wo es um häufiges Datenhin- und herschaufeln geht.
Meiner Erfahrung nach handelt man sich am ehesten mit Listen-Funktionen einen
übergelaufenen Heap ein.

Mit Stringfunktionen ist mir das noch nie passiert.
 
Zuletzt bearbeitet:

Users who are viewing this thread

Zurück
Oben Unten