Какая собственная функция вызывает EXCEPTION_ACCESS_VIOLATION в коде JNI?
Я пытаюсь использовать библиотеку физики маркеров, как обернутую средой разработки Java libgdx для Android (gdx-bullet), и получаю сбои JVM или "чисто виртуальный метод с именем" после некоторого короткого случайного периода работы.
Некоторые из них генерируют файлы hs_err_pidXXXX.log, которые обычно содержат:
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x0aa0c217, pid=7956, tid=7440
#
# JRE version: 7.0_05-b05
# Java VM: Java HotSpot(TM) Client VM (23.1-b03 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [gdx-bullet.dll+0x1c217]
Current thread (0x04af2800): JavaThread "LWJGL Application" [_thread_in_native, id=7440, stack(0x04d70000,0x04dc0000)]
siginfo: ExceptionCode=0xc0000005, reading address 0x6572fc0f
Registers:
EAX=0x0073f370, EBX=0x0073f480, ECX=0x0073f484, EDX=0x6572fc07
ESP=0x04dbf3c0, EBP=0x04dbf400, ESI=0x0073f120, EDI=0x04dbf3f0
EIP=0x0aa0c217, EFLAGS=0x00010206
Instructions: (pc=0x0aa0c217)
0x0aa0c217: ff 52 08 f3 0f 10 05 0c f0 ba 0a f3 0f 10 4c 24
Register to memory mapping:
EDX=0x6572fc07 is an unknown value
Stack: [0x04d70000,0x04dc0000], sp=0x04dbf3c0, free space=316k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [gdx-bullet.dll+0x1c217]
C 0x38cffed8
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j com.badlogic.gdx.physics.bullet.gdxBulletJNI.btDiscreteDynamicsWorld_stepSimulation__SWIG_1(JLcom/badlogic/gdx/physics/bullet/btDiscreteDynamicsWorld;FI)I+0
j com.badlogic.gdx.physics.bullet.btDiscreteDynamicsWorld.stepSimulation(FI)I+7
Мне посоветовали, что это, вероятно, проблема освобождения объекта Java GC от объекта, на который больше нет ссылок в коде Java, но который все еще необходим для встроенного кода пули.
Я просмотрел свой код для них, но не нашел таких ситуаций, что не означает, что их там нет. Я мог бы искать дольше, но я думаю, что если я продолжу использовать этот подход, мне нужно будет научиться самостоятельно отлаживать такие ситуации.
Поэтому я запустил dumpbin.exe на gdx-bullet.dll и обнаружил следующее:
6AB80000 image base (6AB80000 to 6BD4FFFF)
Затем я добавил 0x6AB80000 + 0x1c217 = 0x6AB9C217 и посмотрел это в разборке dumpbin.exe:
6AB9C206: 8B 10 mov edx,dword ptr [eax]
6AB9C208: 89 6C 24 0C mov dword ptr [esp+0Ch],ebp
6AB9C20C: 89 7C 24 08 mov dword ptr [esp+8],edi
6AB9C210: 89 4C 24 04 mov dword ptr [esp+4],ecx
6AB9C214: 89 04 24 mov dword ptr [esp],eax
6AB9C217: FF 52 08 call dword ptr [edx+8]
6AB9C21A: F3 0F 10 05 0C F0 movss xmm0,dword ptr ds:[6AD3F00Ch]
D3 6A
6AB9C222: F3 0F 10 4C 24 30 movss xmm1,dword ptr [esp+30h]
6AB9C228: 80 7E 2C 00 cmp byte ptr [esi+2Ch],0
6AB9C22C: F3 0F 5C C8 subss xmm1,xmm0
Это все хорошо, но это то, где я застрял, потому что я не знаю, что находится в [edx+8].
У меня есть исходный код пули, который был использован (примерно этот).
Я установил windbg.exe и сумел заставить userdump.exe сгенерировать файл javaw.dmp, но не знал, что искать в одном и как. Я попытался выяснить с помощью команды "r", что находится в rdx, но это было 0x0, в отличие от файла hs_err_pid, где это было случайное значение.
Я нашел несколько сценариев сборки, но почему-то сомневаюсь, что могу добавить к ним флаги "включить информацию об отладке", а затем заставить их работать любым способом.
Что я могу сделать, чтобы выяснить, какой именно нативный метод имеет проблему?
Если бы я знал это, то мог бы просмотреть его исходный код и понять, какой неверный параметр я ему передал или какой объект был удален из GC, в котором он нуждается.
1 ответ
Указатель, вероятно, слишком поздно, в вашем случае нарушение доступа происходит из-за доступа к указателю, из которого была выделена память в собственном коде. В этом случае, если память, указанная этим указателем, пытается быть записана, в течение нескольких раз это может фактически работать, если выделенный блок еще не был перераспределен управлением памятью. Я сталкивался с этим в Windows, где в конечном итоге программа выдает ошибку переполнения кучи перед выходом и с конца Java выдает вышеуказанную ошибку. Причина, по которой он работает в течение короткого периода времени, потому что после того, как блок памяти был выделен, он не выделяется сразу Windows, но когда он должен быть перераспределен, Windows проверяет поле заголовка блока памяти и обнаруживает, что он поврежден и, следовательно, ошибка переполнения кучи.
Если нативный код написан вами, вы можете добавить следы и найти проблему, возможно, в обернутой библиотеке вы не сохраняете ссылку на библиотеку в конце Java, или в обертке есть проблема.