[llvm-dev] Contributing a new sanitizer for pointer casts

Stephen Kell via llvm-dev llvm-dev at lists.llvm.org
Wed Apr 26 03:58:09 PDT 2017


Hi Vedant,

> I enjoyed reading through your EuroLLVM slides and OOPSLA paper.
> Detecting the creation of contract-violating pointers is an
> interesting idea, and your paper demonstrates that the checking can
> be comprehensive and effective.

Glad you enjoyed them. :-)

> However, I have concerns about the quality of diagnostics, the
> complexity of the driver, and about maintaining an out-of-tree
> runtime.
> 
> First, I'm concerned about libcrunch diagnostics which are morally
> correct, but which do not point out imminent correctness problems
> (for convenience I'll refer to these as false positives). You address
> this in the "Accommodating Sloppy C" section of your paper with the
> __like_a() runtime check. In my experience, users are reluctant to
> deploy the type of suppressions described here, and are more likely
> to abandon the sanitizer instead. What has your experience been with
> FPs? The results from your SPEC testing look promising, but I'm
> curious about any FP-related feedback you've gotten from other
> developers, or about the results of a libcrunch-enabled world build
> of FreeBSD. 

Great question. The truth is that I don't yet have enough experience to
answer this, and part of the point of contributing this to LLVM would
be to get more people to try it out and contribute improvements.
However, I would say that I am already pleasantly surprised with how
on-point the warnings are... although there are false positives, they
tend to be about genuinely nasty/naughty code. 

I take your point about the danger that "people would turn it off".
As an aside -- more below -- one thing I've worked quite hard on is
to ensure that you don't need to rebuild to turn it off, which at least
prevents a hard exit.

Beyond that, there is quite a long tail of mitigation measures against
false positives, including some not mentioned in the paper (and, er,
some not implemented). The big one, and one that isn't in the paper, is
"trap pointers" -- I outlined this in response to Hal in the TBAA
sanitizer thread. In short, it delays warnings from the time of cast to
the time of use. I only implemented this later, to support bounds
checking rather than cast checking, but it applies to the latter too. 
(Sneak preview: I'm working on bounds checker I believe will offer a
different, possibly better, precision/performance trade-off than ASan,
but that's still in progress.) 

Another possible mitigation is to use "__like_a" by default in some
circumstances, perhaps helped by an up-front static analysis pass to
find things like structure prefixing. That's pure idea-stuff right now.

Doing a build-world of FreeBSD or similar, as you suggest, is exactly
the sort of experience that is required, and inevitably, in doing so
there will be a lot of handle-turning to fix bugs and the like. I'd
rather go through this on an implementation that has a chance of
getting adopted... so I think the LLVM port has to happen first, though
I understand that the contribution per se may have to wait.

> I've certainly seen code at Apple which would fail
> libcrunch's "is-a" checks, but which "works fine" according to the
> code owners. Would you be open to reducing the number of cases
> libcrunch is able to diagnose in order to reduce FP rates?

I'm curious -- can you give me a sketch of what this code is doing? If
it's just a case of "creating wrong-typed pointers that aren't
deref'd", then I think we're good. In general I'd rather fix the FPs
precisely, rather than introduce underapproximation, and I've yet to
see cases where that really can't be done.

> Second, do you see any way to simplify the wrappers required to
> invoke libcrunch? E.g is the runtime preload step necessary? Apart
> from the runtime shared object, can the other tools required to use
> libcrunch be consolidated into the clang binary?

Great question. The plan is to consolidate the tools, yes -- but
probably mostly into the gold plugin. Only a couple of steps work on
the individual compilation units, and they can be deferred until link
time anyhow. It does mean that each compilation unit's allocation site
information has to get dumped somewhere, to be picked up at link time.
This is currently in a .i.allocs text file, but that is a bit untidy...
I've thought about a DWARF extension (DW_TAG_allocation_site or similar)
instead, which would be cleaner.

About preloading -- I happen to like this design, modulo the
clunky invocation, because it means you can easily turn the checking on
or off. For executables, you could simply link the preload stuff in,
but that would lose the on/off switch, and doesn't work for shared
libraries. Another idea I've had is to use a customised loader (ld.so)
instead of a preload library. So you would do

$ ./myprogram   # runs normally

or 

$ /path/to/crunchld.so ./myprogram    # runs +crunch

This would more-or-less replicate the usage model of Valgrind tools.
(In general, my feeling is that extending the ld.so is more sane than
using LD_PRELOAD, although I realise it will seem a bit off-the-wall.)

> Third, how do you plan on keeping the libcrunch integration into
> clang in-sync with the runtime, if the runtime is to live outside of
> the llvm tree? 

I think that part is no problem. The interface between instrumented
code and the runtime is pretty narrow (basically just the __is_a(),
__like_a() and similar functions) and does not embed any LLVM stuff, so
it would be stable under LLVM churn. The same would hold for the gold
plugin... LLVM/clang's involvement is mostly just to do the
instrumentation, which is a pretty well-isolated task. The allocation
site metadata I just mentioned is probably the only change-prone thing.

Of course, there is a problem of breakage/churn in the
libcrunch/liballocs stuff... in particular, things like new DWARF
features can break things. I have no good answer to that, except that
more hands make light(er) work.

> How will the feature be tested? 

On that, I have no idea, and I'd have to take your lead on that. To
make an analogy with another out-of-tree dependency, how do you test
LTO against GNU binutils? I'm hoping, perhaps naively, that it could
work similarly.

> Currently, the
> sanitizer runtimes ship with official LLVM downloads: what would the
> deployment story for libcrunch be (how would users get it)?

Initially they would build the libcrunch tree, which would build for
them the gold plugin and runtime. Again, I think it would be rather
like the LTO story (a web page with "follow these instructions"). And
of course distributors could build binary packages... again, it helps
that the interface between compiler and plugin/runtime is fairly simple.

(Full disclosure: currently you have to build both the liballocs tree
and the libcrunch tree, separately. Eventually the former will be a
submodule of the latter. I have too many levels of submodule going
on....)

> I don't mean any of this as a "do not proceed" message. These are
> simply some of the issues which I think are worth discussing early on.

Of course. :-) Thanks for the detailed comments! Hoping my answers make
sense, and happy to follow up,

Stephen.


More information about the llvm-dev mailing list