In order to get started with stoat let’s consider using it on an existing program. For this brief tutorial we will use non-timeline. The first step is going to be downloading the non tools.

git clone https://github.com/original-male/non

Now, in order to get the LLVM IR bitcode files, the -emit-llvm argument needs to be passed to clang, however this does result in output files which cannot be linked together with ld. For a number of build systems, this results in a reasonable claim that the compiler cannot produce usable binaries. To avoid this we can sneak this flag in after most of the configuration. The needed patch is shown below.

diff --git a/wscript b/wscript
index f6118c6..29305e3 100644
--- a/wscript
+++ b/wscript
@@ -136,6 +136,7 @@ def configure(conf):
for i in pl:
Logs.pprint('YELLOW', 'Configuring %s' % i)
conf.recurse(i);
+    conf.env.append_value('CXXFLAGS', ['-emit-llvm'] )

def run(ctx):
if not Options.options.cmd:

With this out of the way, the build system can produce the LLVM intermediate files. For now this will fail once the build system gets to linking, but in the future a wrapper script will likely be used in place of this hackery.

CXX=clang++ ./waf configure
./waf || ./waf || ./waf

Now it is possible to process the project. To verify the previous steps just run stoat --recursive . . This should produce no errors, but it should list the files that it processed to get zero errors. In order for it to actually produce useful results some function needs to be whitelisted. This can be done either with inline attributes or via external whitelists. Let’s just make an external whitelist named "non-whitelist.txt" with the below contents:

Engine::process

With this done rerun stoat:

stoat --recursive . --whitelist non-whitelist.txt --graph-view non-callgraph.png

Now a list of errors should be produced, along with the graph view. The error list right now directly prints out the internal structure showing the deductions needed to find something contradictory. The first few errors are shown below:

"warnf(warning_t, char const*, char const*, char const*, int, char const*, ...)"
#<DeductionChain:0x87d479c
@deduction_source="_ZN6Engine7processEj",
@has_body_p=true,
@non_realtime_p=false,
@realtime_p=true,
@reason=
"The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function">
##The Deduction Chain:
- Engine::process(unsigned int) : The Function Was Declared Realtime By A Whitelist
- fprintf : No Code Or Annotations, So The Function is Assumed Unsafe
- fputs : No Code Or Annotations, So The Function is Assumed Unsafe
- vfprintf : No Code Or Annotations, So The Function is Assumed Unsafe
- fwrite : No Code Or Annotations, So The Function is Assumed Unsafe

"sigc::internal::signal_emit1<int, double, sigc::nil>::emit(sigc::internal::signal_impl*, double const&)"
#<DeductionChain:0x8749750
#<Set: {"_ZN4sigc9slot_baseC1Ev",
"_ZNSt8__detail15_List_node_base9_M_unhookEv",
"_ZdlPv",
"_ZN4sigc8internal11signal_impl5sweepEv"}>,
@deduction_source="_ZN9Transport4pollEv",
@has_body_p=true,
@non_realtime_p=false,
@realtime_p=true,
@reason=
"The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function">
##The Deduction Chain:
- Transport::poll() : The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function
- Engine::process(unsigned int) : The Function Was Declared Realtime By A Whitelist
- sigc::slot_base::slot_base() : No Code Or Annotations, So The Function is Assumed Unsafe
- std::__detail::_List_node_base::_M_unhook() : No Code Or Annotations, So The Function is Assumed Unsafe
- operator delete(void*) : No Code Or Annotations, So The Function is Assumed Unsafe
- sigc::internal::signal_impl::sweep() : No Code Or Annotations, So The Function is Assumed Unsafe

"Playback_DS::process(unsigned int)"
#<DeductionChain:0x8747cd4
@deduction_source="class.Playback_DS4",
@has_body_p=true,
@non_realtime_p=false,
@realtime_p=true,
@reason=
"The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function">
##The Deduction Chain:
- class.Playback_DS4 : The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function
- Track::process_output(unsigned int) : The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function
- Timeline::process_output(unsigned int) : The Function Was Deduced To Need To Be RealTime As It Was Called By A Realtime Function
- Engine::process(unsigned int) : The Function Was Declared Realtime By A Whitelist
- usleep : No Code Or Annotations, So The Function is Assumed Unsafe