Rekursionsabsicherung QM und SMs umgebaut
Statt auf einen Zeitstempel zu gehen, wird jetzt die DI_EVAL_NUMBER
dafuer benutzt, welche bei jeder neuen Toplevel-Ausfuehrung vom
Driver erhoeht wird. Wenn die Toplevel-Ausfuehrung abgeschlossen
ist, ist die Rekursion abgeschlossen und daher ist das ein besseres
Merkmal als ein sekundengenauer Zeitstempel.
Change-Id: Iabc28d7618b8f5a8caf6870c4f45307d434fb87f
diff --git a/std/thing/properties.c b/std/thing/properties.c
index 5852704..18d076f 100644
--- a/std/thing/properties.c
+++ b/std/thing/properties.c
@@ -17,6 +17,8 @@
#pragma range_check
#pragma no_clone
+#include <driver_info.h>
+
#define NEED_PROTOTYPES
#include "/sys/thing/properties.h"
@@ -35,7 +37,10 @@
// This is empty outside of a save_object() or restore_object() call!
private mapping properties;
-// security-flag
+// security-flag: wenn gesetzt und es gleich der aktuellen DI_EVAL_NUMBER ist,
+// ist dieser Ausfuehrungsthread in einer Auswertung von F_QUERY/SET_METHOD
+// (ggf. rekursiv) und es wird jeder Aufruf als extern gewertet bzgl.
+// PROTECTED/SECURED.
private nosave int closure_call;
@@ -71,15 +76,15 @@
// Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
// selber, EM+ oder ROOT veraendert werden.
- // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv'
- // zu ersetzen, weil extern_call() das default-argument fuer <drop_priv>
- // ist. Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des
- // Aufrufers ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist,
- // muessen wir dennoch selber pruefen. Wir glauben aber immer, wenn es 1
- // ist und der Aufrufer Privilegien abgeben will.
- if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
- (closure_call||drop_priv||extern_call()) &&
- previous_object() != this_object() && !allowed())
+ // Es ist verfuehrerisch, das 'drop_priv||extern_call()' durch 'drop_priv' zu
+ // ersetzen, weil extern_call() das default-argument fuer <drop_priv> ist.
+ // Das ist keine gute Idee, weil <drop_priv> unter der Kontrolle des Aufrufers
+ // ist und dieser 0 uebergeben kann. Sprich: wenn es 0 ist, muessen wir
+ // dennoch selber pruefen. Wir glauben aber immer, wenn es 1 ist, der
+ // Aufrufer hat nichts davon und das eigene Objekt darf Privilegien abgeben.
+ drop_priv = drop_priv||extern_call()||closure_call==driver_info(DI_EVAL_NUMBER);
+ if ((prop[F_MODE][name]&(PROTECTED|SECURED))
+ && drop_priv && previous_object() != this_object() && !allowed())
return -1;
// Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
@@ -88,10 +93,8 @@
return -2;
// Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
- // 'drop_priv||extern_call()' ist Absicht, s.o.
- if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
- (closure_call || drop_priv || extern_call()) &&
- previous_object() != this_object() && !allowed() )
+ if ((Type==F_MODE||Type==F_MODE_AS) && (Value&SECURED)
+ && drop_priv && previous_object() != this_object() && !allowed() )
return -3;
switch(Type)
@@ -154,8 +157,6 @@
mixed func = prop[F_SET_METHOD][name];
if (func)
{
- int flag;
-
// Wert als Set-Method? gleich zurueckgeben
if (!closurep(func)) return func;
@@ -164,8 +165,9 @@
// Objekt existiert auch noch (sonst waere func == 0).
// closure_call setzen, falls noch nicht gesetzt
- if ((flag=closure_call<time()))
- closure_call = time()+59;
+ int set_closure_call = closure_call != driver_info(DI_EVAL_NUMBER);
+ if (set_closure_call)
+ closure_call = driver_info(DI_EVAL_NUMBER);
// Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
if (catch(result=funcall(func, Value, name);publish))
@@ -173,8 +175,10 @@
prop[F_SET_METHOD]-=([name]);
}
- // Wenn closure_call gesetzt wurde, wieder loeschen
- if (flag) closure_call = 0;
+ // Wenn dieser Aufruf closure_call gesetzt hat, wieder loeschen.
+ // Da 0 ein gueltiger Wert ist, wird um eins dekrementiert, damit das Flag
+ // fuer diese Top-Level-Ausfuehrung wieder freigegeben.
+ if (set_closure_call) --closure_call;
// Und zurueckgeben
return result;
@@ -203,8 +207,6 @@
mixed func = prop[F_QUERY_METHOD][name];
if (func)
{
- int flag;
-
// Wert als Query-Method? Gleich zurueckgeben ...
if (!closurep(func)) return func;
@@ -213,16 +215,19 @@
// Objekt existiert auch noch (sonst waere func == 0).
// closure_call setzen, falls noch nicht gesetzt
- if ((flag=closure_call<time()))
- closure_call = time()+59;
+ int set_closure_call = closure_call != driver_info(DI_EVAL_NUMBER);
+ if (set_closure_call)
+ closure_call = driver_info(DI_EVAL_NUMBER);
// Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
if (catch(result=funcall(func);publish))
{
prop[F_QUERY_METHOD]-=([name]);
}
- // Wenn closure_call gesetzt wurde, wieder loeschen
- if (flag) closure_call = 0;
+ // Wenn dieser Aufruf closure_call gesetzt hat, wieder loeschen.
+ // Da 0 ein gueltiger Wert ist, wird um eins dekrementiert, damit das Flag
+ // fuer diese Top-Level-Ausfuehrung wieder freigegeben.
+ if (set_closure_call) --closure_call;
// Und zurueckgeben
return result;
@@ -279,7 +284,7 @@
if(!mappingp(props)) return;
// Setzen wir selber?
- same_object = (!closure_call &&
+ same_object = (closure_call!=driver_info(DI_EVAL_NUMBER) &&
(!extern_call()||previous_object()==this_object()||
allowed()));
names = m_indices(props);