dylan-lang / opendylan

Open Dylan compiler and IDE
http://opendylan.org/
Other
458 stars 69 forks source link

Forward reference to thread variable segfaults #590

Open cgay opened 11 years ago

cgay commented 11 years ago

Open Dylan 2013.1 OS X

In testworks I was rearranging the code into different files and started getting a segfault during library initialization. It was fairly hard to debug. Turned out to be a forward reference to a thread variable in a different file. i.e., the file occurred later in the LID file. Here's a library that reproduces the problem:

==> library.dylan <==
module: dylan-user

define library segfault
  use common-dylan;
  use io;
end library;

define module segfault
  use common-dylan, exclude: { format-to-string };
  use format-out;

==> segfault1.dylan <==
module: segfault

define function main (name :: <string>, arguments :: <vector>)
  format-out("Hello, %s!\n", *thread-variable*);
  exit-application(0);
end;

main(application-name(), application-arguments());

==> segfault2.dylan <==
module: segfault

define thread variable *thread-variable* = "world";

==> segfault.lid <==
library: segfault
files: library
  segfault1
  segfault2
cgay-macbookpro2:segfault cgay$ lldb _build/bin/segfault
Current executable set to '_build/bin/segfault' (i386).
(lldb) process launch
process launch
Process 63839 launched: '/Users/cgay/dylan/src/segfault/_build/bin/segfault' (i386)
Process 63839 stopped
* thread #1: tid = 0x1d2c87, 0x00109cd2 libdylan.dylib`primitive_read_thread_variable(h=0x001389c4) + 34 at posix-threads.c:1548, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x922630)
    frame #0: 0x00109cd2 libdylan.dylib`primitive_read_thread_variable(h=0x001389c4) + 34 at posix-threads.c:1548
(lldb) bt
bt
* thread #1: tid = 0x1d2c87, 0x00109cd2 libdylan.dylib`primitive_read_thread_variable(h=0x001389c4) + 34 at posix-threads.c:1548, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x922630)
    frame #0: 0x00109cd2 libdylan.dylib`primitive_read_thread_variable(h=0x001389c4) + 34 at posix-threads.c:1548
    frame #1: 0x00004e71 libsegfault.dylib`_Init_segfault__X_segfault1_for_user [inlined] KmainVsegfaultI + 42 at segfault1.c:112
    frame #2: 0x00004e47 libsegfault.dylib`_Init_segfault__X_segfault1_for_user + 23 at segfault1.c:144
    frame #3: 0x00004d1a libsegfault.dylib`_Init_segfault_ + 74 at _glue.c:24
    frame #4: 0x8fe13cda dyld`ImageLoaderMachO::doModInitFunctions(ImageLoader::LinkContext const&) + 230
    frame #5: 0x8fe13fde dyld`ImageLoaderMachO::doInitialization(ImageLoader::LinkContext const&) + 64
    frame #6: 0x8fe10268 dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 356
    frame #7: 0x8fe101cc dyld`ImageLoader::recursiveInitialization(ImageLoader::LinkContext const&, unsigned int, ImageLoader::InitializerTimingList&) + 200
    frame #8: 0x8fe100ba dyld`ImageLoader::runInitializers(ImageLoader::LinkContext const&, ImageLoader::InitializerTimingList&) + 62
    frame #9: 0x8fe01e05 dyld`dyld::initializeMainExecutable() + 211
    frame #10: 0x8fe05adb dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3050
    frame #11: 0x8fe01376 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 704
    frame #12: 0x8fe01077 dyld`_dyld_start + 71
cgay commented 10 months ago

The variable/constant needn't be a thread variable. I just ran into the same problem with protocol buffers, in which I tried to update an $introspection-data table with top-level code that occurred in a file before it was defined.

Since we do library-at-a-time compilation, I assume that we have a view of all the definitions regardless of file. We may or may not currently be able to infer a complete ordering? It would be great if we could emit a serious warning for such code ("attempt to use $introspection-data which is not yet initialized") and not segfault.

cgay commented 10 months ago

I'm dropping this here on the theory that it's a similar/related issue.

I have top-level code that makes an instance of <dylan-field-descriptor-proto>, which is defined in a subsequent file. (I'm pretty certain this is illegal, so this is really just about improving the failure mode.) The test suite dies with this error when it attempts to access a field in the class via field-descriptor-proto-name. So I'm guessing that the top-level code that makes the instance somehow executes without error but hasn't correctly initialized the class object?

$ $PB/../_build/bin/protocol-buffers-test-suite --debug crashes --test 'test-<file-descriptor-set>-introspection'
Test test-<file-descriptor-set>-introspection:
#f is not of type {<class>: <integer>}
Backtrace:
  0
  default-handler:dylan:dylan##1 + 0x12
  0x79643a6e616c7964
  default-last-handler:common-dylan-internals:common-dylan##0 + 0x2f6
  error:dylan:dylan##0 + 0x27
  type-check-error:internal:dylan + 0x6d
  make-slot-access-engine-node:dispatch-engine-internal:dylan + 0x238
  transmogrify-method-list-grounded:dispatch-engine-internal:dylan + 0x28c
  compute-terminal-engine-node:dispatch-engine-internal:dylan + 0x8b
  compute-discriminator-for-arg:dispatch-engine-internal:dylan + 0x2a4
  compute-dispatch-from-root:dispatch-engine-internal:dylan + 0x2b
  Kanonymous_of_PPtest_Lfile_descriptor_setG_introspectionF51I + 0x13
  do-check-equal:%testworks:testworks + 0x335
  %%test-<file-descriptor-set>-introspection:protocol-buffers-test-suite:protocol-buffers-test-suite + 0x261
  Kanonymous_of_execute_componentF95I + 0x360
  do-with-profiling:common-dylan-internals:common-dylan + 0x2f
  execute-component:%testworks:testworks##1 + 0x2cd
  maybe-execute-component:%testworks:testworks##0 + 0x193
  run-tests:testworks:testworks + 0x88
  run-or-list-tests:%testworks:testworks + 0x71
  run-test-application:testworks:testworks + 0x413
  main + 0x19
  __libc_start_main + 0xea
  _start + 0x2a