Thanks for the reply, but I'm not sure how much of that I'm going to be able to use. You called ROOT::B->new() outside the compartment, which isn't what I want. If you move it back inside reval it doesn't work again.
Also, in the real app, the untrusted code isn't going to be written by me (that's why it's untrusted :-) and I don't really want it to have to be changed at all. I did have a quick go at modifying the code as it went in, and after it had been evaled (patching up @ISA to include the compartment root) but it still didn't fly. Putting the packages in files isn't really an option either, since I don't want to allow require/use inside, or any access to the filesystem.
I'm beginning to think that I'm not going to be able to use Safe as-is because of the namespace thing, but I'll have to do something similar myself.