- Trivialize the mapping of the
defwebapp
form to adefclass
form, putting most of the logic in initializing methods and possibly a metaclass (ahem, class metaobject class). - Don't hide the default slot values in
class-default-initargs
. - On reevaluation of
defwebapp
, replace the slot values, at least in the trivial case where the hacker allowed the normal autostarter to instantiate the resultingweblocks-webapp
subclass.
My first thought, abandoned before I could even start changing
defwebapp
proper to use it, would have defwebapp
fill class-instance slots (not to be confused with instance slots with :allocation :class) instead of default-initargs
, then alter the initform and initfunction in compute-effective-slot-definition
to copy over those values to each new instance.
(defclass weblocks-webapp-class (standard-class)
())
(defmethod validate-superclass ((class weblocks-webapp-class) superclass)
(typep (class-name (class-of superclass))
'(member standard-class weblocks-webapp-class)))
(defgeneric class-defaulting-slots (class)
(:method ((self weblocks-webapp-class))
(loop for class in (class-precedence-list self)
while (typep class 'weblocks-webapp-class)
append (class-direct-slots class)))
(:method ((self standard-class)) '()))
(defmethod compute-effective-slot-definition
((self weblocks-webapp-class) name direct-slot-defns)
"Provide a default initform (read the class's version of the slot)
for those without initforms."
(let ((eslot (call-next-method))
(defaulting-slots (class-defaulting-slots self)))
(macrolet ((initfunc () (slot-definition-initfunction eslot)))
(when (and (find name defaulting-slots :key #'slot-definition-name)
(not (initfunc)))
(setf (slot-definition-initform eslot)
`(slot-value (find-class ',(class-name self)) ',name)
(initfunc) (lambda () (slot-value self name)))))
eslot))
No comments:
Post a Comment