
I would do something like this: > (require errortrace)
> (require "the-student-file.rkt")

If that also changes the printing parameters, then you might need to reset those individually in-between

But note that you want to do that sequence at the top-level, not in a module.

Is it possible to define a contract for a message passing interface? Say, a procedure, that accepts predefined messages and their respective return contract(s). I thought this would work: (define message/c (or/c (-> 'foo foo/c)
(-> 'bar bar/c)
(-> 'etc etc/c)))
However, it complains because multiple branches are satisfied, per the documentation for or/c
: > If more than one returns true, it also signals a contract violation.

Actually, that approach doesn’t seem to work on either front: no error tracing, and no student language printing.

@sorawee We’ve got a #lang directive at the top of the student file, so yeah.

@racket741 It looks like first-or/c
might be what you want? (I’ve never used it, in fact never heard of it until looking right now at the or/c
docs. first-or/c
is the next item documented.)

I gave first-or/c
a shot, but that also gives a violation

Maybe case->
is what you need

I did not get an error in this silly example I just tried: #lang racket
(define foo/c 'foo)
(define bar/c 'bar)
(define message/c (first-or/c (-> 'foo foo/c)
(-> 'bar bar/c)))
(define/contract (handle-message v)
message/c
v)
(handle-message 'foo)
` But maybe I need more coffee.

It works with (handle-message 'foo)
but it will fail on (handle-message 'bar)

So I’ll go get more coffee soon. :smile: As @yfangzhe mentioned maybe case->
is relevant.

case->
looks like it should do the right thing, but I just tried and again it fails. It has the same behaviour as first-or/c
: the first message works, the subsequent messages give a violation, complaining that it’s expecting the first message

Maybe you need ->i
to express that the contract is about a single function, and the range (result) varies based on the domain (parameter)?

(Having said that: When I’ve done “message handlers” in Racket, they tend not to have contracts like this. They’re essentially a cond
or match
expression, and the default/else clauses is what emits an error message. But maybe that’s not good for what you’re doing.)

(Sometimes I’ll make each sort of message its own little struct
. Maybe they all derive from a message
struct
. And then I get match
patterns as well as struct predicates to use, in various ways.)

I’m just “playing”, so it’s highly likely I’m not doing this idiomatically — likewise, my handler is just a cond
. I was just wondering if there was a way of “identifying” that closure such that it can be used elsewhere per the “poor man’s object”

@greg Thanks :slightly_smiling_face: Your suggestion of ->i
worked — again, forgive the lack of idomaticity (I just tweaked the example in the docs): (define message/c (->i ((msg (symbols 'foo 'bar)))
(result (msg) (cond ((equal? msg 'foo) foo/c)
((equal? msg 'bar) bar/c)))))

@leif I added support for dotted identifiers in assignments.

Is Racket using any particular CI infrastructure these days? I took a quick look and it seems to me Racket has rolled its own.

http://drdr.racket-lang.org\|drdr.racket-lang.org is our own, but we also use GitHub Actions.

I’m still working on the segfault, what’s the best way to debug a segfault for the main Racket process?

BC

Would running a backtrace under GDB do anything useful?

Yes. To get a good stacktrace, you typically have to run a different binary; probably it’s the one in racket/src/build/racket/racket3m

Also, on Linux, when you start gdb, use signal SIGSEGV nostop noprint
to avoid stopping on write barriers

you also need to avoid stopping on SEGV, run handle SIGSEGV nostop noprint

jinx

(But if you’re on a Mac, you don’t need to do that. And you’ll likely use lldb
.)

Thanks!

@bsaiki has joined the channel

If you can get valgrind to work, I find that it’s more useful for SEGFAULT since the problem may have started much earlier before the crash.

Unfortunately getting useful results from valgrind on racket is not easy

I’m not sure if my local dev setup is messed up or what, but there seems to be both ~/Library/Racket/development/doc/
and ~/git/racket/racket/doc
. If we don’t count the fact that the latter hosts the actual documentations from various collections, both directories are pretty much identical (docindex.sqlite
, CSS files, JS files, search). Why do we need an extra one?
What’s even weirder is that local doc viewing seems to use content from both (search functionality from the former, actual doc from the latter).

If you add packages in user scope, then ~/Library/Racket/development
will have that package’s documentation, but the installation directory won’t. The user-specific documentation entry point will link to all of the installation’s documentation, though.

so at startup, racket loads algol 60 and a bunch of other stuff. which ones are essential and which ones can be disabled?

or is the impact of loading them really negligible at startup?

DrRacket (which is what I think you mean) does load a bunch of tools at startup. You can disable any of them. None of them are “essential”, but lots of them are useful depending on what you’re doing.

@bsaiki

gdb doesn’t report anything, but it definitely segfaults when run normally. Am I totally missing something here?

as in, it run successfully and finishes?

yep

You could try enabling core files and then using gdb on the core file. But it would also make sense to just send me the program (assuming that the example is not too unweildy).

Ok. I’ll try that

It seems that:

Calling herbie ...
causes a segfaul

Sorry I have my enter/newline inverted

But calling racket src/herbie.rkt ...
or racket3m src/herbie.rkt
does not cause a segfault. Not sure why that is. I changed the herbie
shell to instead call racket3m
and I got a core dump with symbols, but it doesn’t look very helpful. Text of the core dump follows…

(gdb) thread apply all bt full
Thread 3 (Thread 0x7fbba706d700 (LWP 5324)): #0 0x00007fbba6dd53bf in GI_clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fbba706c2c0, rem=rem@entry=0x0) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78 sc_cancel_oldtype = 0 sc_ret = <optimized out> r = <optimized out> #1 0x00007fbba6ddb047 in GI_nanosleep (requested_time=requested_time@entry=0x7fbba706c2c0, remaining=remaining@entry=0x0) at nanosleep.c:27 ret = <optimized out> #2 0x00007fbba6e0d9bf in usleep (useconds=<optimized out>) at ../sysdeps/posix/usleep.c:32 ts = {tv_sec = 0, tv_nsec = 10000000} #3 0x000056403269233e in ?? () No symbol table info available. #4 0xfffffffffffff410 in ?? () No symbol table info available. #5 0x0000564033a5d200 in ?? () No symbol table info available. #6 0x0000564032692300 in ?? () No symbol table info available. #7 0x000056403262d2de in ?? () No symbol table info available. #8 0x0000000000000000 in ?? () No symbol table info available.
Thread 2 (Thread 0x7fbb9bfcf700 (LWP 5325)): #0 0x00007fbba6d3c322 in GI_sigtimedwait (set=set@entry=0x7fbb9bfce270, info=info@entry=0x7fbb9bfce1a0, timeout=timeout@entry=0x0) at ../sysdeps/unix/sysv/linux/sigtimedwait.c:29 resultvar = 18446744073709551612 sc_cancel_oldtype = 0 sc_ret = <optimized out> result = <optimized out> #1 0x00007fbba6efbf6c in sigwait (set=0x7fbb9bfce270, sig=0x7fbb9bfce26c) at ../sysdeps/unix/sysv/linux/sigwait.c:28 si = {si_signo = 17, si_errno = 0, si_code = 1,pad0 = 0, _sifields = {_pad = {5362, 1000, 0, 0, 0, 0, 1, 0 <repeats 21 times>}, _kill = {si_pid = 5362, si_uid = 1000}, _timer = {si_tid = 5362, si_overrun = 1000, si_sigval = {sival_int = 0, sival_ptr = 0x0}}, _rt = {si_pid = 5362, si_uid = 1000, si_sigval = {sival_int = 0, sival_ptr = 0x0}}, _sigchld = {si_pid = 5362, si_uid = 1000, si_status = 0, si_utime = 0, si_stime = 1}, _sigfault = {si_addr = 0x3e8000014f2, si_addr_lsb = 0, _bounds = {_addr_bnd = {_lower = 0x0, _upper = 0x1}, _pkey = 0}}, _sigpoll = {si_band = 4294967301362, si_fd = 0}, _sigsys = {_call_addr = 0x3e8000014f2, _syscall = 0, _arch = 0}}} ret = <optimized out> #2 0x000056403278d28e in ?? () No symbol table info available. #3 0x00007fbb9bfce26c in ?? () No symbol table info available. #4 0x00007fbb9bfce270 in ?? () No symbol table info available. #5 0x0000000000000000 in ?? () No symbol table info available.
Thread 1 (Thread 0x7fbba6cf1300 (LWP 5319)): #0 GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 set = {val = {66562, 0 <repeats 15 times>}} pid = <optimized out> tid = <optimized out> —Type <RET> for more, q to quit, c to continue without paging—c ret = <optimized out> #1 0x00007fbba6d1a859 in GI_abort () at abort.c:79 save_stage = 1 act = {sigaction_handler = {sa_handler = 0x1, sa_sigaction = 0x1}, sa_mask = {_val = {140443577188360, 24, 52, 0, 0, 0, 0, 0, 0, 0, 94833724474172, 94833744372944, 25, 94833745006880, 94833724482731, 94833744205040}}, sa_flags = –445038480, sa_restorer = 0x7fbb9a24cdb8} sigs = {_val = {32, 0 <repeats 15 times>}} #2 0x000056403275e685 in ?? () No symbol table info available. #3 0x0000000000000000 in ?? () No symbol table info available.

Can you disassem in the vicinity of 0x000056403275e685? Probably something like disassem 0x000056403275e645, 0x000056403275e6c5

0x000056403275e645: Cannot access memory at address 0x56403275e645

Oh 685?

Same thing. Can’t access memory

I was trying to hit a range of addresses around the one in the track trace. But I guess the crash is that a jump is made to a bad code address.

Oh ok. Got it

Yay…thank you

i have a question, how do i call create-embedding-executable
so it behaves like raco exe --gui <file.rkt>

Here is a working example: https://github.com/alex-hhh/ActivityLog2/blob/4f749a78ea52d3c71f6f531b1d73eb05c26f8dbc/build.rkt#L111

thank you!