Wiki

Ticket #261 (closed defect: wontfix)

Opened 7 years ago

Last modified 7 years ago

circular contracts cause mono to segfault

Reported by: blubb Owned by: Chuck
Priority: major Milestone:
Component: Cobra Compiler Version: 0.8.0
Keywords: Cc:

Description

the following code causes mono to crash with a SIGSEGV:

class Oops

    def oneMore as int
        ensure
            result == .oneLess + 1
        body
            print "oneMore executed"
            return 3

    def oneLess as int
        ensure
            result == .oneMore - 1
        body
            print "oneLess executed"
            return 2

    def main
        .oneMore

Output:

$ ./oops.exe
oneMore executed
oneLess executed
oneMore executed
oneLess executed
oneMore executed
[... ~15'000 of these ...]
Stacktrace:


Native stacktrace:

	/usr/bin/cli() [0x47b77f]
	/usr/bin/cli() [0x4aef3f]
	/lib/libpthread.so.0(+0xfb40) [0x7f3912fc0b40]
	/usr/bin/cli() [0x4aee86]
	/lib/libpthread.so.0(+0xfb40) [0x7f3912fc0b40]
	[0x402cd7c7]

Debug info from gdb:

82	../sysdeps/unix/syscall-template.S: No such file or directory.
Cannot access memory at address 0x7fffe72a3f80
[Thread debugging using libthread_db enabled]
[New Thread 0x7f39118a1710 (LWP 15767)]
[New Thread 0x7f3913b0e710 (LWP 15766)]
0x00007f3912fbfb8d in read () at ../sysdeps/unix/syscall-template.S:82
	in ../sysdeps/unix/syscall-template.S
  3 Thread 0x7f3913b0e710 (LWP 15766)  0x00007f3912fc036d in nanosleep () at ../sysdeps/unix/syscall-template.S:82
  2 Thread 0x7f39118a1710 (LWP 15767)  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86
* 1 Thread 0x7f3913cb8740 (LWP 15764)  0x00007f3912fbfb8d in read () at ../sysdeps/unix/syscall-template.S:82

Thread 3 (Thread 0x7f3913b0e710 (LWP 15766)):
#0  0x00007f3912fc036d in nanosleep () at ../sysdeps/unix/syscall-template.S:82
#1  0x0000000000556342 in ?? ()
#2  0x00007f3912fb8971 in start_thread (arg=<value optimized out>) at pthread_create.c:304
#3  0x00007f3912a9191d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#4  0x0000000000000000 in ?? ()

Thread 2 (Thread 0x7f39118a1710 (LWP 15767)):
#0  sem_wait () at ../nptl/sysdeps/unix/sysv/linux/x86_64/sem_wait.S:86
#1  0x00000000004e4aaa in ?? ()
#2  0x0000000000505035 in ?? ()
#3  0x0000000000570073 in ?? ()
#4  0x000000000058de21 in ?? ()
#5  0x00007f3912fb8971 in start_thread (arg=<value optimized out>) at pthread_create.c:304
#6  0x00007f3912a9191d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112
#7  0x0000000000000000 in ?? ()

Thread 1 (Thread 0x7f3913cb8740 (LWP 15764)):
#0  0x00007f3912fbfb8d in read () at ../sysdeps/unix/syscall-template.S:82
#1  0x000000000047b8f4 in ?? ()
#2  0x00000000004aef3f in ?? ()
#3  <signal handler called>
#4  0x00000000004aee86 in ?? ()
#5  <signal handler called>
#6  0x00000000402cd7c7 in ?? ()

=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

There are several options to deal with contracts that circularly reference themselves:

  • detect and warn at compile-time
  • detect and report error at compile-time
  • when executing contracts, do not go deeper than <arbitraryNumber> stack frames. when the limit is exceeded, just assume the contract to be fulfilled. (this is what Eiffel does)

Either way, the larger programs become, the harder it is to write contracts that do not contain circles in their dependency graph. In my experience (<rant>as a student of Bertrand Meyer, who was forced to write LOTS of contracts</rant>), as soon as you started thinking about what contracts you may use where, contracts turn from a useful feature into nuisances. Also, implementing the solution Eiffel uses will really piss people off. After all, if they specify contracts, they expect them to fail if a condition is not met.

Change History

Changed 7 years ago by Chuck

  • status changed from new to assigned
  • owner set to Chuck

Yeah I can't see implementing the Eiffel approach as you describe it because it masks the fact that the contracts are ill-defined.

Now correct me if I'm wrong, but this is not an actual contract issue. You can get the same problematic behavior with simple methods:

class A
	def main
		.foo(List<of int>())
	def foo(t as List<of int>)
		.bar(Set<of int>())
	def bar(s as Set<of int>)
		.foo(List<of int>())

And Mono will also crash on that. It is very unfortunate that they don't throw StackOverflowException like .NET. Since this bad Mono behavior is at the virtual machine level, it is out of our direct control.

However, Cobra can add additional code per method to catch the problem and in fact already offers this as a by-product of using the DetailedStackTrace option. The wiki page describing that fails to mention the stack overflow detection as does "cobra -h". So these need to be updated. I'm also starting a StackOverflow wiki page.

Changed 7 years ago by Chuck

  • status changed from assigned to closed
  • resolution set to wontfix

I have included the sentence "Also, detects stack overflow which is needed for Mono but not .NET which already does this." in the help text for "cobra -h" and the DetailedStackTrace page.

I'm closing this ticket.

Note: See TracTickets for help on using tickets.