-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Afterburner MyClassLoader#loadAndResolve()
is not idempotent when tryToUseParent
is true
#49
Comments
Ah. Thank you for very thorough investigation into gnarly edge case. I'll try to get your solution integrated. |
Fix MyClassLoader idempotency - issue #49
MyClassLoader#loadAndResolve()
is not idempotent when tryToUseParent
is true
@cowtowncoder I think we've seen a few occurrences of this bug in production - if you're expecting 2.9.9 to be released soon, then I'd love to pick it up! Otherwise, we'll probably build a snapshot from develop and jam that into our classpath. |
This is from a while ago, but |
…mpotency Fix MyClassLoader idempotency - issue FasterXML#49
The
MyClassLoader
used by the Afterburner module checks to see if it has already loaded a class with the given name and short-circuits, but it does not check whether the parent class loader has already loaded the requested class:ClassLoader#defineClass
fails with a LinkageError when a class with the same name has already been defined, so the second time that a generated class with the same base name and bytecode is loaded by afterburner, the attempt to define it on the parent class loader will fail and silently fall through to define it on theMyClassLoader
itself. This will succeed, and produce no ill effect in most circumstances.However, when the bean class being deserialized is a private inner class (as is commonly seen in bean classes generated by the Immutables framework), it is necessary that the class loader into which afterburner injects its custom instantiator class be the same as the class loader which loaded the private inner class itself, or else an
IllegalAccessError
will occur during deserialization.Under typical operations, afterburner will only generate a specific custom instantiator class once, but when two threads, each using an
ObjectMapper
with the sameClassLoader
instance both attempt to deserialize the same type at the same time (for the first time), both threads can end up trying to define the same custom instantiator bytecode at almost exactly the same time. The first thread to make the attempt will define the new class on the "parent" class loader. The second attempt will fail to define the (now already existing) class on the parent class loader, and will fall back to defining it on the MyClassLoader itself. If the class being deserialized is a private inner class, the second thread will subsequently throw an IllegalAccessError during deserialization, and all further attempts to deserialize that type will also throw the same error.I believe that
MyClassLoader#loadAndResolve
should first check to see if the parent class loader has loaded the requested class, then proceed with the logic of the method as written. Something like this at the top of the method:The text was updated successfully, but these errors were encountered: