Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Author here. I noticed before both mdb support and the Delve project that other have mentioned, and I find them great. The point of my excitement for godebug resides in the fact that it's an easy to work with, zero complexity added tool to replace most tedious println() debugging sessions. That is, the non-exciting stuff.

Not all bugs only happen on production load, architecture, etc. Many times (with DNS servers even more so, I'd say) bugs are simple state or logic bugs. The Heisenbugs exist. The complex resource-constrained races exist. And I find it fun to track them down, but many bugs are much more mundane, and godebug is a great tool for catching those.

Speaking instead about hard to trace production bugs, I think the Go design and library deserve their daily share of praise here, since they solve many of those problems. Take Valgrind (or ASAN). Amazing tools. Completely useless in Go -- the language is memory-safe and will make that kind of bugs both hard to introduce and immediately detectable.

And about concurrency, first of all the simple design makes bugs harder to introduce and easier to reason about. But even when they make their way in I find provisions like net/http/pprof and its various profile a pleasure to work with. And finally there's obviously the race detector.

Still, I can't wait to see more tools developed to cover different Go debugging needs. Today I'm just happy about making my println() session much more pleasant and elegant :)



The enthusiasm is fine -- I just wish it were couched in the understanding of the limitations of the technique. I also think it's naive to say that Go's design solves "many [production] problems" -- memory-safe languages solve one set of problems, but often introduce or exacerbate another. (The most obvious example being memory exhaustion: postmortem heap analysis is often much easier on a C-based system than in memory-safe languages.[1][2]) More generally, do not fall into the trap of correctness from smugness: nasty production bugs can exist in any language, and time is much better spent on the production tooling to debug such problems rather than simply asserting that such bugs are tautologically impossible.

[1] http://dtrace.org/blogs/ahl/2004/07/13/number-11-of-20-libum...

[2] https://queue.acm.org/detail.cfm?id=2039361

Edit: added a much better reference.


> (The most obvious example being memory exhaustion: postmortem heap analysis is often much easier on a C-based system than in memory-safe languages.[1])

This is a problem of GC, not of memory safety. Memory safety does not require GC.

> More generally, do not fall into the trap of correctness from smugness: nasty production bugs can exist in any language, and time is much better spent on the production tooling to debug such problems rather than simply asserting that such bugs are tautologically impossible.

The failure modes of the lack of memory safety range from "annoying crash due to null pointer dereference" up to "millions of users at risk of 0-day RCE due to use after free". When the stakes are that high, it's worth spending time to attack those bug classes systematically as opposed to just tackling these bugs in production one-by-one.


Your assertion that "this is a problem of GC, not of memory safety" is incorrect (and I never asserted that GC was the core problem). Memory safety does require a layer of indirection between the native system and the programmer, and that layer introduces opacity to the native system that necessitates its own layer of custom tooling to see through. And memory exhaustion is (obviously!) not a problem restricted to GC'd environments -- any program in any (modern, Turing complete) environment can allocate memory to the point of process death!


> Memory safety does require a layer of indirection between the native system and the programmer, and that layer introduces opacity to the native system that necessitates its own layer of custom tooling to see through.

No, it doesn't. That's literally what Rust (what I worked/work on) is all about. Memory safety is all done at compile time, and it's boiled away to direct access to the platform's native memory subsystem. Platform-native tooling "just works", and I use it every day.


That's terrific, and apologies if you feel I've slighted Rust at all. (I admire Rust's goals to deliver safety without compromising performance or debuggability.) From a native perspective, two things I would love to see with respect to Rust: first, a comment on Alex Light's work[1], as alternative allocators like libumem are often essential for debuggability. Second, I would love to see the applicability of native techniques like postmortem object type identification[2] to Rust. If that "just works" it would be reason alone to seriously evaluate Rust!

[1] http://scialex.github.io/reenix.pdf

[2] http://arxiv.org/pdf/cs/0309037v1.pdf


No worries, and apologies if I seemed snippy. Thanks for the fascinating link on postmortem object type identification; now I have some reading to do :)


The blog post you referenced in [1] doesn't mention managed language runtimes itself, so let me make sure I understand the point. If I understand your point correctly, it's that with managed language runtimes, particularly mature ones like HotSpot and V8, the C heap isn't used in the typical C way; instead, the runtime has its own heap, closely integrated with the garbage collector. In that case, Go probably has the same problem, just because it tries not to use libc at all. I'm guessing that CPython isn't as bad, because it doesn't use a garbage collector. No idea about Ruby.


Yes -- and you understand the point correctly. And it's independent of whether a language is GC'd or not; to provide memory safety means to provide a layer of indirection between the system's notion of memory and that of the run-time -- and that layer becomes opaque to traditional native tools. I apologize that that reference was a little hasty; [1] is a much, much better one.

[1] https://queue.acm.org/detail.cfm?id=2039361


> And it's independent of whether a language is GC'd or not; to provide memory safety means to provide a layer of indirection between the system's notion of memory and that of the run-time -- and that layer becomes opaque to traditional native tools.

No! You can enforce memory safety at compile time and use the platform's native memory allocation subsystem. There's no need for memory safety to imply any extra runtime support.


As far as I can tell you're right in principle, but even Rust doesn't currently deliver that in practice. With Rust 1.0, at least on Linux, Rust uses its own bundled jemalloc rather than the libc malloc. So IIUC, that means that you can't take advantage of things like libumem, the alternative malloc described in the blog post bcantrill referenced a few comments ago.


Yeah, I figured someone would bring up jemalloc. :) As of a few days ago, Rust allocation is pluggable [1]. jemalloc is considered a "feature" in the Cargo sense which can be turned on and off. (The immediate impetus for this feature work was to use HeapAlloc() on Windows.)

[1]: https://github.com/rust-lang/rust/blob/master/src/liballoc/h...


> postmortem heap analysis is often much easier on a C-based system than in memory-safe languages.

For a specific kind of leak. Java heapdumps and MAT are great postmortem heap-debugging tools (of course, Java Flight Recorder is even awesomer, but unfortunately not part of OpenJDK).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: