ReadyTalk / avian

[INACTIVE] Avian is a lightweight virtual machine and class library designed to provide a useful subset of Java's features, suitable for building self-contained applications.
https://readytalk.github.io/avian/
Other
1.22k stars 172 forks source link

invokedynamic leads to accessing null dynamicTable in addDynamic. #564

Open Poddster opened 6 years ago

Poddster commented 6 years ago

I'm hitting a null pointer crash in Avian, somewhere in the guts of handling an invokedynamic instruction. This is with avian in "compile mode". It doesn't matter if Avian is compiled with the JDK image/source or with Avian's classpath.

This was compiled and run on x64 Ubuntu 16.04.5 LTS and another Linux-based ARM platform.

The crash details from debugger:

CLICK ME: Backtrace from lldb ```text Process 14395 stopped * thread #3: tid = 14399, 0x00007ffff7af5564 libjvm.so`(anonymous namespace)::local::addDynamic(t=0x0000555555971c58, invocation=0x00007fffe401e758)::local::MyThread *, vm::GcInvocation *) + 1482 at compile.cpp:1373, name = 'avian-dynamic', stop reason = signal SIGSEGV: invalid address (fault address: 0x8) frame #0: 0x00007ffff7af5564 libjvm.so`(anonymous namespace)::local::addDynamic(t=0x0000555555971c58, invocation=0x00007fffe401e758)::local::MyThread *, vm::GcInvocation *) + 1482 at compile.cpp:1373 1370 compileRoots(t)->dynamicThunks()->body()[index * 2] = thunk; 1371 compileRoots(t)->dynamicThunks()->body()[(index * 2) + 1] = size; 1372 -> 1373 t->dynamicTable[index] = reinterpret_cast(thunk); 1374 1375 roots(t)->invocations()->setBodyElement(t, index, invocation); 1376 } (lldb) thread backtrace * thread #3: tid = 14399, 0x00007ffff7af5564 libjvm.so`(anonymous namespace)::local::addDynamic(t=0x0000555555971c58, invocation=0x00007fffe401e758)::local::MyThread *, vm::GcInvocation *) + 1482 at compile.cpp:1373, name = 'avian-dynamic', stop reason = signal SIGSEGV: invalid address (fault address: 0x8) * frame #0: 0x00007ffff7af5564 libjvm.so`(anonymous namespace)::local::addDynamic(t=0x0000555555971c58, invocation=0x00007fffe401e758)::local::MyThread *, vm::GcInvocation *) + 1482 at compile.cpp:1373 frame #1: 0x00007ffff7b0638f libjvm.so`(anonymous namespace)::local::compile(t=0x0000555555971c58, initialFrame=0x00007ffff0de8ed0, initialIp=0, exceptionHandlerStart=-1)::local::MyThread *, (anonymous namespace)::local::Frame *, unsigned int, int) + 21271 at compile.cpp:5289 frame #2: 0x00007ffff7b0e96e libjvm.so`(anonymous namespace)::local::compile(t=0x0000555555971c58, context=0x00007ffff0de9040)::local::MyThread *, (anonymous namespace)::local::Context *) + 1242 at compile.cpp:7378 frame #3: 0x00007ffff7b2375e libjvm.so`(anonymous namespace)::local::compile(t=0x0000555555971c58, allocator=0x000055555575d290, bootContext=0x0000000000000000, method=0x00007fffe401f5a0)::local::MyThread *, avian::util::FixedAllocator *, (anonymous namespace)::local::BootContext *, vm::GcMethod *) + 488 at compile.cpp:10664 frame #4: 0x00007ffff7b15bd5 libjvm.so`(anonymous namespace)::local::MyProcessor::invokeList(this=0x000055555575d1e8, t=0x0000555555971c58, method=0x00007fffe401f5a0, this_=0x0000000000000000, indirectObjects=false, arguments=0x00007ffff0de9320) const + 757 at compile.cpp:9187 frame #5: 0x00007ffff7ad110b libjvm.so`vm::Processor::invoke(this=0x000055555575d1e8, t=0x0000555555971c58, method=0x00007fffe401f5a0, this_=0x0000000000000000) + 215 at processor.h:207 frame #6: 0x00007ffff7ab54f8 libjvm.so`vm::initClass(t=0x0000555555971c58, c=0x00007fffe401f6a0) + 312 at machine.cpp:5267 frame #7: 0x00007ffff7b2362b libjvm.so`(anonymous namespace)::local::compile(t=0x0000555555971c58, allocator=0x000055555575d290, bootContext=0x0000000000000000, method=0x00007fffe401f458)::local::MyThread *, avian::util::FixedAllocator *, (anonymous namespace)::local::BootContext *, vm::GcMethod *) + 181 at compile.cpp:10633 frame #8: 0x00007ffff7b1780c libjvm.so`(anonymous namespace)::local::compileMethod2(t=0x0000555555971c58, ip=0x000000004005b08c)::local::MyThread *, void *) + 248 at compile.cpp:9645 frame #9: 0x00007ffff7b0f02d libjvm.so`(anonymous namespace)::local::compileMethod(t=0x0000555555971c58)::local::MyThread *) + 110 at compile.cpp:7472 frame #10: 0x000000004000001b frame #11: 0x00007ffff7b13337 libjvm.so`(anonymous namespace)::local::invoke(thread=0x0000555555971c58, method=0x00007ffff10def78, arguments=0x00007ffff0de9b70)::local::ArgumentList *) + 597 at compile.cpp:8555 frame #12: 0x00007ffff7b15bf2 libjvm.so`(anonymous namespace)::local::MyProcessor::invokeList(this=0x000055555575d1e8, t=0x0000555555971c58, method=0x00007ffff10def78, this_=0x0000555555897460, indirectObjects=false, arguments=0x00007ffff0de9c20) const + 786 at compile.cpp:9189 frame #13: 0x00007ffff7ad110b libjvm.so`vm::Processor::invoke(this=0x000055555575d1e8, t=0x0000555555971c58, method=0x00007ffff10def78, this_=0x0000555555897460) + 215 at processor.h:207 frame #14: 0x00007ffff7b2fda7 libjvm.so`(anonymous namespace)::local::MyClasspath::runThread(this=0x0000555555758538, t=0x0000555555971c58) const + 179 at classpath-openjdk.cpp:622 frame #15: 0x00007ffff7ae0c50 libjvm.so`vm::runJavaThread(t=0x0000555555971c58) + 73 at machine.h:1806 frame #16: 0x00007ffff7ae0cff libjvm.so`vm::runThread(t=0x0000555555971c58, (null)=0x0000000000000000) + 152 at machine.h:1820 frame #17: 0x00007ffff7b7efe6 libjvm.so`vmRun + 47 frame #18: 0x00007ffff7ae0b5a libjvm.so`vm::runRaw(t=0x0000555555971c58, function=(libjvm.so`vm::runThread(vm::Thread*, unsigned long*) at machine.h:1812), arguments=0x0000000000000000)(vm::Thread*, unsigned long*), unsigned long*) + 78 at machine.h:1793 frame #19: 0x00007ffff7ae0bda libjvm.so`vm::run(t=0x0000555555971c58, function=(libjvm.so`vm::runThread(vm::Thread*, unsigned long*) at machine.h:1812), arguments=0x0000000000000000)(vm::Thread*, unsigned long*), unsigned long*) + 83 at machine.h:1801 frame #20: 0x00007ffff7ae096c libjvm.so`vm::Thread::Runnable::run(this=0x0000555555971ce0) + 72 at machine.h:1769 frame #21: 0x00007ffff7a94c01 libjvm.so`(anonymous namespace)::run(r=0x0000555555971ce0) + 50 at posix.cpp:101 frame #22: 0x00007ffff6f846ba libpthread.so.0`start_thread + 202 frame #23: 0x00007ffff77c441d libc.so.6`__clone + 109 at clone.S:109 ```

Probing some variables a bit further:

CLICK ME: print of the Thread variable in debugger ```text (lldb) frame variable *t error: libjvm.so 0x000002a5: DW_TAG_member '__size' refers to type 0x000002bc which extends beyond the bounds of 0x00000221 error: libjvm.so 0x00000357: DW_TAG_member '__size' refers to type 0x00000375 which extends beyond the bounds of 0x000002d7 ((anonymous namespace)::local::MyThread) *t = { vm::Thread = { vtable = 0x000055555575d9f8 m = 0x000055555575d898 parent = 0x00005555557628d8 peer = 0x00005555558d0558 child = 0x0000000000000000 waitNext = 0x0000000000000000 state = ActiveState criticalLevel = 0 systemThread = 0x0000555555972630 lock = 0x00005555559725d0 javaThread = 0x0000555555897460 exception = 0x0000000000000000 heapIndex = 7303 heapOffset = 8190 protector = 0x00007ffff0de8ce0 classInitStack = 0x00007ffff0de9480 libraryLoadStack = 0x0000000000000000 resource = 0x00007ffff0de8640 checkpoint = 0x00007ffff0de99f0 runnable = { t = 0x0000555555971c58 } defaultHeap = 0x0000555555a91cd8 heap = 0x00007fffe4011968 backupHeap = { [0] = 0 [1] = 0 [2] = 0 [3] = 0 [4] = 0 [5] = 0 [6] = 0 [7] = 0 [8] = 0 [9] = 0 [10] = 0 [11] = 0 [12] = 0 [13] = 0 [14] = 0 [15] = 0 [16] = 0 [17] = 0 [18] = 0 [19] = 0 [20] = 0 [21] = 0 [22] = 0 [23] = 0 [24] = 0 [25] = 0 [26] = 0 [27] = 0 [28] = 0 [29] = 0 [30] = 0 [31] = 0 [32] = 0 [33] = 0 [34] = 0 [35] = 0 [36] = 0 [37] = 0 [38] = 0 [39] = 0 [40] = 0 [41] = 0 [42] = 0 [43] = 0 [44] = 0 [45] = 0 [46] = 0 [47] = 0 [48] = 0 [49] = 0 [50] = 0 [51] = 0 [52] = 0 [53] = 0 [54] = 0 [55] = 0 [56] = 0 [57] = 0 [58] = 0 [59] = 0 [60] = 0 [61] = 0 [62] = 0 [63] = 0 [64] = 0 [65] = 0 [66] = 0 [67] = 0 [68] = 0 [69] = 0 [70] = 0 [71] = 0 [72] = 0 [73] = 0 [74] = 0 [75] = 0 [76] = 0 [77] = 0 [78] = 0 [79] = 0 [80] = 0 [81] = 0 [82] = 0 [83] = 0 [84] = 0 [85] = 0 [86] = 0 [87] = 0 [88] = 0 [89] = 0 [90] = 0 [91] = 0 [92] = 0 [93] = 0 [94] = 0 [95] = 0 [96] = 0 [97] = 0 [98] = 0 [99] = 0 [100] = 0 [101] = 0 [102] = 0 [103] = 0 [104] = 0 [105] = 0 [106] = 0 [107] = 0 [108] = 0 [109] = 0 [110] = 0 [111] = 0 [112] = 0 [113] = 0 [114] = 0 [115] = 0 [116] = 0 [117] = 0 [118] = 0 [119] = 0 [120] = 0 [121] = 0 [122] = 0 [123] = 0 [124] = 0 [125] = 0 [126] = 0 [127] = 0 [128] = 0 [129] = 0 [130] = 0 [131] = 0 [132] = 0 [133] = 0 [134] = 0 [135] = 0 [136] = 0 [137] = 0 [138] = 0 [139] = 0 [140] = 0 [141] = 0 [142] = 0 [143] = 0 [144] = 0 [145] = 0 [146] = 0 [147] = 0 [148] = 0 [149] = 0 [150] = 0 [151] = 0 [152] = 0 [153] = 0 [154] = 0 [155] = 0 [156] = 0 [157] = 0 [158] = 0 [159] = 0 [160] = 0 [161] = 0 [162] = 0 [163] = 0 [164] = 0 [165] = 0 [166] = 0 [167] = 0 [168] = 0 [169] = 0 [170] = 0 [171] = 0 [172] = 0 [173] = 0 [174] = 0 [175] = 0 [176] = 0 [177] = 0 [178] = 0 [179] = 0 [180] = 0 [181] = 0 [182] = 0 [183] = 0 [184] = 0 [185] = 0 [186] = 0 [187] = 0 [188] = 0 [189] = 0 [190] = 0 [191] = 0 [192] = 0 [193] = 0 [194] = 0 [195] = 0 [196] = 0 [197] = 0 [198] = 0 [199] = 0 [200] = 0 [201] = 0 [202] = 0 [203] = 0 [204] = 0 [205] = 0 [206] = 0 [207] = 0 [208] = 0 [209] = 0 [210] = 0 [211] = 0 [212] = 0 [213] = 0 [214] = 0 [215] = 0 [216] = 0 [217] = 0 [218] = 0 [219] = 0 [220] = 0 [221] = 0 [222] = 0 [223] = 0 [224] = 0 [225] = 0 [226] = 0 [227] = 0 [228] = 0 [229] = 0 [230] = 0 [231] = 0 [232] = 0 [233] = 0 [234] = 0 [235] = 0 [236] = 0 [237] = 0 [238] = 0 [239] = 0 [240] = 0 [241] = 0 [242] = 0 [243] = 0 [244] = 0 [245] = 0 [246] = 0 [247] = 0 [248] = 0 [249] = 0 [250] = 0 [251] = 0 [252] = 0 [253] = 0 [254] = 0 [255] = 0 } backupHeapIndex = 0 flags = 160 } ip = 0x00000000400520c1 stack = 0x00007ffff0de9818 newStack = 0x00007ffff0de95d0 scratch = 0x00007ffff0de9928 continuation = 0x0000000000000000 exceptionStackAdjustment = 0 exceptionOffset = 0 exceptionHandler = 0x0000000000000000 tailAddress = 0x0000000000000000 virtualCallTarget = 0x0000000000000000 virtualCallIndex = 0 heapImage = 0x0000000000000000 codeImage = 0x0000000000000000 thunkTable = 0x000055555575d3a8 dynamicTable = 0x0000000000000000 trace = 0x00007ffff0de9a20 reference = 0x0000000000000000 arch = 0x0000555555763250 transition = 0x0000000000000000 traceContext = 0x0000000000000000 stackLimit = 140737234377120 referenceFrame = 0x0000000000000000 methodLockIsClean = true } (lldb) frame variable *t->m->processor->dynamicTable (void *) *t->m->processor->dynamicTable = 0x000000004005adf0 ```

.

From that we can see that dynamicTable was set by the rest of the code in addDynamic for the t->m->processor, but this doesn't appear to have been copied over to the t->dynamicTable field? I think it might be a simple case of a missing call to updateDynamicTable(t, t); or something like that?? That might be understating the problem, however.

Example application that results in this crash: https://github.com/Poddster/avian_null_dynamicTable

That app is the smallest I can make it, though smaller examples might exist. Changing practically anything in this example app makes the problem disappear. (Infact using that information I've managed to make my original app not crash by working around the issue and accessing a class earlier than it normally would. This seems to "fix" the problem for me, though the underlying issue is obviously still present.)