Open ingo-budde opened 4 years ago
On 2020-06-24 05:57:06 -0700, Ingo Budde wrote:
The method
Scene.getSootClassUnsafe()
already makes use of thesynchronized
keyword to guard against race conditions and also provides special logic for the dummy classSootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME
, but the current implementation cannot completely prevent the three following edge cases:Just for the record: we also have a potential fix [1] [2], which we are currently testing/evaluating:)
[1] https://github.com/fraunhofer-iem/soot-umbrella/commit/a0552d59e05438b30ccc73b3f33822edd7f23eb2 [2] https://github.com/fraunhofer-iem/soot-umbrella/tree/bugfix/fix_data_race_in_getSootClassUnsafe
Thanks for the in-depth report. Any updates on this issue?
On 2020-07-15 02:31:35 -0700, Manuel Benz wrote:
Thanks for the in-depth report. Any updates on this issue?
Unfortunately, our "internal" testing got delayed a bit... (in fact, it just started a few hours ago:/ )
Are you "blocked" on this issue? (If so, you can give the referenced patch (see my previous reply) a try.)
I'll try to push this a bit so that we can file a PR ASAP. Sorry for the delay...
I also encountered the same problem. With the same application code, most of the time soot succeeds, but sometimes it throws "duplicate class: soot.dummy.InvokeDynamic" error, so it does look like a race condition error. Error msg as blow. Looking forward to the fix.
java.lang.RuntimeException: Failed to convert <com.alibaba.intl.nyse.gateway.driver.pp.rule.refund.AbstractRefundRequestRule: void lambda$buildRefundRequest$3(java.util.Map,com.alibaba.intl.nyse.gateway.driver.pp.rule.refund.InstrumentRefundBuildRequest,com.taobao.payment.facade.req.v2.RefundRequest,java.util.concurrent.atomic.AtomicReference,com.alibaba.intl.nyse.ability.refund.model.extra.FullRefundInstrument)>
at soot.asm.AsmMethodSource.getBody(AsmMethodSource.java:2062)
at soot.SootMethod.retrieveActiveBody(SootMethod.java:402)
at soot.PackManager$1.run(PackManager.java:1279)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.RuntimeException: duplicate class: soot.dummy.InvokeDynamic
at soot.Scene.addClassSilent(Scene.java:822)
at soot.Scene.addClass(Scene.java:803)
at soot.SootResolver.makeClassRef(SootResolver.java:128)
at soot.RefType.getSootClass(RefType.java:118)
at soot.Scene.getSootClassUnsafe(Scene.java:1153)
at soot.Scene.getSootClassUnsafe(Scene.java:1136)
at soot.Scene.getSootClass(Scene.java:1177)
at soot.asm.AsmMethodSource.convertInvokeDynamicInsn(AsmMethodSource.java:1406)
at soot.asm.AsmMethodSource.convert(AsmMethodSource.java:1813)
at soot.asm.AsmMethodSource.getBody(AsmMethodSource.java:2060)
... 5 more
Are you "blocked" on this issue? (If so, you can give the referenced patch (see my previous reply) a try.)
We are also victim to this bug. I'm not blocked by it, however. I just wanted to check-in if you are making progress with a fix.
I'll try to push this a bit so that we can file a PR ASAP. Sorry for the delay...
It's not an issue, thanks for investigating the problem!
On 2020-07-17 02:40:39 -0700, Manuel Benz wrote:
I'll try to push this a bit so that we can file a PR ASAP. Sorry for the delay...
It's not an issue, thanks for investigating the problem!
I just created PR#1390.
We identified three bugs that are probably caused by data races in the implementation of
Scene.getSootClassUnsafe()
. We are already experimenting with a potential solution and we will provide a merge request for that soon. Thanks to Marcus Hüwe (@marcus-h) for the problem analysis and detailed explanations below.The method
Scene.getSootClassUnsafe()
already makes use of thesynchronized
keyword to guard against race conditions and also provides special logic for the dummy classSootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME
, but the current implementation cannot completely prevent the three following edge cases:Issue 1: For a given className, several SootClass instances are created
For this, assume two threads are calling
Scene.getSootClassUnsafe(SootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME, true)
and there exists no RefType namedSootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME
. In this case, it is possible that both threads end up executing the following code:Consequently, two
SootClass
instances are created where only one of them will be associated with RefType type afterwards. This could lead to potential issues. Note that the secondaddClassSilent()
call does not result in a "duplicate class" RuntimeException because theSootClass(...)
constructor (indirectly) callsRefType.setSootClass(this)
, which causesScene.containsClass()
to returnfalse
when called inScene.addClassSilent()
.Issue 2: "duplicate class: soot.dummy.InvokeDynamic" RuntimeException
For this, first create "several" class files that contain invokedynamic instructions.
Next, execute soot (and keep fingers crossed to see some "bad" interleaving;) )
For instance, this can occur if two threads (Thread-7 and Thread-1) call
Scene.getSootClassUnsafe(SootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME, true)
and interleave as follows:When Thread-7 calls
addClassSilent(c)
, theSootClass
instance that was created by Thread-1 is associated with theRefType
type and also part of theScene
(that is,Scene.containsClass()
returnstrue
). Hence, the "duplicate class: soot.dummy.InvokeDynamic" RuntimeException is thrown.Issue 3: DANGLING resolving level during method resolution
For this, reuse the class files from Issue 2 and execute soot (again, keep fingers crossed to see a "bad" interleaving).
Note: the
--validate
option is needed in order to trigger the method resolution.As in Issue 2, this is, again, due to some bad interleaving of (at least) two threads that call
Scene.getSootClassUnsafe(SootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME, true)
, which is indirectly called fromsoot.asm.AsmMethodSource.convertInvokeDynamicInsn()
, which is indirectly called fromPackManager.retrieveAllBodies
.That is, in
soot.asm.AsmMethodSource.convertInvokeDynamicInsn()
a newSootMethodRef(Impl)
is constructed where the declaring class has aDANGLING
resolving level. Hence, theRuntimeException
is thrown when resolving thisSootMethodRefImpl
instance (in Thread-10).