qom: Split out object and class caches
The object-cast and class-cast caches cannot be shared because class caching is conditional on the target type not being an interface and object caching is unconditional. Leads to a bug when a class cast to an interface follows an object cast to the same interface type: FooObject = FOO(obj); FooClass = FOO_GET_CLASS(obj); Where TYPE_FOO is an interface. The first (object) cast will be successful and cache the casting result (i.e. TYPE_FOO will be cached). The second (class) cast will then check the shared cast cache and register a hit. The issue is, when a class cast hits in the cache it just returns a pointer cast of the input class (i.e. the concrete class). When casting to an interface, the cast itself must return the interface class, not the concrete class. The implementation of class cast caching already ensures that the returned cast result is only a pointer cast before caching. The object cast logic however does not have this check. Resolve by just splitting the object and class caches. Cc: qemu-stable@nongnu.org Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Tested-by: Nathan Rossi <nathan.rossi@xilinx.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> Signed-off-by: Andreas Färber <afaerber@suse.de>
This commit is contained in:
parent
c272758f93
commit
0ab4c94c84
@ -358,7 +358,8 @@ struct ObjectClass
|
||||
Type type;
|
||||
GSList *interfaces;
|
||||
|
||||
const char *cast_cache[OBJECT_CLASS_CAST_CACHE];
|
||||
const char *object_cast_cache[OBJECT_CLASS_CAST_CACHE];
|
||||
const char *class_cast_cache[OBJECT_CLASS_CAST_CACHE];
|
||||
|
||||
ObjectUnparent *unparent;
|
||||
};
|
||||
|
13
qom/object.c
13
qom/object.c
@ -458,7 +458,7 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
||||
Object *inst;
|
||||
|
||||
for (i = 0; obj && i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
if (obj->class->cast_cache[i] == typename) {
|
||||
if (obj->class->object_cast_cache[i] == typename) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@ -475,9 +475,10 @@ Object *object_dynamic_cast_assert(Object *obj, const char *typename,
|
||||
|
||||
if (obj && obj == inst) {
|
||||
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
obj->class->cast_cache[i - 1] = obj->class->cast_cache[i];
|
||||
obj->class->object_cast_cache[i - 1] =
|
||||
obj->class->object_cast_cache[i];
|
||||
}
|
||||
obj->class->cast_cache[i - 1] = typename;
|
||||
obj->class->object_cast_cache[i - 1] = typename;
|
||||
}
|
||||
|
||||
out:
|
||||
@ -547,7 +548,7 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
||||
int i;
|
||||
|
||||
for (i = 0; class && i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
if (class->cast_cache[i] == typename) {
|
||||
if (class->class_cast_cache[i] == typename) {
|
||||
ret = class;
|
||||
goto out;
|
||||
}
|
||||
@ -568,9 +569,9 @@ ObjectClass *object_class_dynamic_cast_assert(ObjectClass *class,
|
||||
#ifdef CONFIG_QOM_CAST_DEBUG
|
||||
if (class && ret == class) {
|
||||
for (i = 1; i < OBJECT_CLASS_CAST_CACHE; i++) {
|
||||
class->cast_cache[i - 1] = class->cast_cache[i];
|
||||
class->class_cast_cache[i - 1] = class->class_cast_cache[i];
|
||||
}
|
||||
class->cast_cache[i - 1] = typename;
|
||||
class->class_cast_cache[i - 1] = typename;
|
||||
}
|
||||
out:
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user