 So hi everyone, I'm Jules. I'm a software engineer at Facebook in London, and I work on the infer team So infer is not that Sorry Who's cream no definitely not play. Thank you. Why did it know that works? so infer is a Static analyzer it's open source so you can find it on github And it ships with a number of analysis by default That do a range of things the most advanced of which is a Memory safety analysis that tries to flag bugs about null pointer exceptions or memory resource leaks or double free or the like And it also has Simpler analysis all the way to linters that you there's even a small DSL to define your own syntactic checks on on the code for instance And and one of the defining characteristic of them more complex analysis in infer is that are inter procedural So that means they are able to flag issues that involve several procedures at once possibly in several files so in the rest of the talk I'll explain a Bit about infers architecture and how it does inter procedural analysis and in at a high level and I will also explain how we deploy it at Facebook where it does deep time analysis Okay, so Infer starts from a project which is some source files and build system to to build these files and It's architecture like a compiler. So there first. There's a front end that takes source code in the source language so Java or languages supported by clang and Much like a compiler. It translates them into a much simpler and common tool languages IR that is called SIL and SIL is Much simpler than Java or C++ is just basically loads and stores and function calls and go-to's Then once all the source files have been translated into infers language the back-end analysis run and and for so for each procedure they compute a summary of the procedure in Isolation of all the other procedures and they are stored as what we call specs So there's one specification for each procedure and this is also the point where errors are flagged So most of the analysis work by trying to establish that the procedure has no bug and when there's a failure in that proof Then a bunch of heuristics kick in to classify the failure of the proof either as a weakness in the analyzer or as something that Looks more like a bug that we should report And so at the end of the analysis we collect all these issues we found and we we build a report Okay, let's do mean into the front-end how it works So there are two front-ends one for clang languages and one for Java. I would describe them both So we start with the project the source code and the build system and now we need to find Where the where the code lives so we act we ask the build system actually so the way you would run in fur is just typing For instance info dash dash make and info will do all the work of figuring out Figuring out what to do and the way it works is it runs the build system and capture calls to the compiler That happened during compilation And so it records for each source file the way to it records that allows it to discover which source file should be analyzed and how they are compiled and So it's a bit of a It's not the most robust bust of infer because you have to do this work for each build system All the build systems are different and there's no sort of unified way to extract the information of how to build files Given the build system. So that's a bit annoying if you have a few no solutions to this problem. Please talk to me So but we have integrations for a few build systems and That works so if it's a Java file, then we call Java C to get Java bytecode and Then our Java from turn actually starts from the bytecode and not the Java source and Translates Java bytecode into SIL and If it's clang then we run clang To compile the file and we attach our own clang plugin that dumps the clang AST in some serialized format that our frontend is able to read from OCaml and translate also into SIL So and There's also the place where we plug or clang linters So because here we see the AST we can run this source code very syntactic analysis that just matches nodes in the AST and make some reports And So we are able to do that for clang but not for Java because Java we started the bytecode level so There's no linters for Java in infer at the moment. So that was the frontend Let's look at the back end now. So And the back end takes procedures that were translated by the frontend and it tries to find specifications for them So there are many analysis in infer as I said They're all based on the same architecture that is compositional and on demand So it's compositional that means that it will schedule the analysis to look at each procedure in isolation without looking at the calling context of each procedure or Or the arguments with which the procedure is called. So the analysis each analysis has to be Smart enough to be able to work on a procedure without knowing anything about where it's called and in exchange that allows us to Reuse the summary computed for the procedure in all the calling context. So that allows infer to scale very nicely And the architecture is also on demand What I mean by that is that each procedure is only analyzed if it's needed for The analysis and it's analyzed when it's needed So let's look at an example I'm going to use the allocates memory checker that we have as an example. So that's a checker That reports whenever a function is allocated with no allocation like goo here But it calls a function that eventually allocates memory So let's see how this works. So let's say we're only interested in analyzing the functions in a food at Java so we start with one of them like food and We see that it calls bar. So we need to compute the summary for bar first. So we go do that Notice that bar here is another file Also, I've written this as more or less Java code, but it's actually in the intermediate language of infer So infer analysis bar and it noticed that it allocates memory Online 3 so that's the summary it computes It remembers that the only thing it will remember about bar now is that's on line 3 that locates memory so we come back to food and now we know that food also allocates memory because And we recall the reason why we think it recall it allocates memory and that's because it calls bar on line 3 the reason we We recall the reason why there's a bug is because when we're going to report later It's going to be very important that we give some idea of where there's a bug to the user So then we look at goo it calls food and so We go look at foo and see that its specification says its allocates so goo also allocates and Because a goo is mark no allocation we report here so Not also that in goo we only Recall that it calls foo and we don't follow all the chain of explanation This will be reconstructed only when needed when we report so that it scales more Okay, so that's on demand analysis But inter procedural issues and so One thing we were wondering at some point is how important is it that the analysis is composite is Interprocedural sorry, and so we did this case today of bugs that were reported by info recently And we counted for each of them if they were interprocedural, so we sorted them in three buckets one is Bugs that you can find just by looking at one procedure in one file the second bucket is Bugs you can find by looking at all the procedures in but only in one file and the third category is Bugs that involve multiple procedures that span multiple files And what we found is that for some bug types the majority of the bugs were in the last category So so it's very important So being interprocedural and inter file gives the best signal to developers and So this is Allocates memory that we saw and this one is a bit particular because almost all the bugs it reports span multiple files and All the way at the bottom. There's bite pointer comparison, which is a linter and so linter only looks at VST of 1.5 so and surprisingly it only reports Intrap procedural bugs Okay, so how do we deploy infer at Facebook, so I said it's It reports at diff time so when whenever a developer sends a new change It will go through our CI system and our CI system runs a bunch of tests And it also schedules an analysis via infer and this is this Happens all at the same time as human reviewers are reading the code and making comments and so infer it with Commenting on the div just as other human reviewers will so If it finds a bug it reports it on fabricator, which is our code review tool That's also open source and infer comments look just like other human reviewer comments So in that case that's a report. That's a report generated by infer that says that there might be another reference in caused by the diff and one important point is that In this integration infer we only surfaced the bugs that infer finds that were introduced by the diff And only if they were in files that were touched by the diff And the reason we do that is that that's what the developer quarantine Context on and is working on this change and so is able to act on on these warnings Much more than on warnings about unrelated things so at some points And Infer is happy with the diff and all the code reviewers are happy about the diff and so then It makes it into the code base and into our products So let's go back to our example and see how diff analysis works a bit more in details So let's say that our diff was the diff that introduced the call to foo in the no allocation method So that's the the state of the code after the diff. That's what we saw earlier So we know that infer does this on that version of the code It reports the error on goo because it calls foo that allocates So then what info we'll do is it will analyze the base commit the version of the code without the diff so in this version goo doesn't call foo and Also, we need to reanalyze foo that Java because that's the file that was modified so infer Analyzes foo again It needs bar. It already has a spec for bar and this one doesn't need to change because we know that bar hasn't changed And so it will Computer get that foo allocates by a bar and Then when you analyze this foo goo, it says that it does nothing. There's no allocation there So now that you did this to analysis of the base on the diff It knows that on the base there was no report on the div There was just one report about foo and so what it will report to the user is What was reported on the diff minus what would be reported on the base? So it will report the new error So this debate the playground model has been quite successful so far We find that it helps developers move fast And give them more confidence about their code changes because infer will check that they don't introduce too many bugs It also makes life easy for us because it makes it very much easier to deploy new checks Because we only report new bugs introduced by diffs So even if a new analysis that we ship has a legacy of thousands of bugs in the code base we don't need to care about this right now because Developers will not see them because they were already there that we only see the new ones that they introduce So we find that quite valuable For instance The another situation that's not like this is compiler warnings I find they're always a pain to enable them projects because there are always so many pre-existing warnings and you can never turn the Wanting you want into an error straight away because you have to fix all the pre-existing one first. So So this this kind of deployment avoids that issue Okay, so that's more or less it's the current status is infer runs on old diffs for Android and our iOS apps as well as our c++ backend and that represents tens of thousands of diffs every month and There are thousands of issues fixed every month out of all the ones reported by infer and and That's about a 70% fixed rate and the fixed rate is what we measure as giving good signal to developers is It's the proportion of reports That's we're fixed by developers as they were reported by infer and That's That's the metric we take and not some other metrics like false positives or things like this because that's a metric we can actually measure So that's why it's important to us. Okay. That's all I had to say. Thanks for listening any questions Yes In the example with memory location, what if the location happens conditionally depending on one of the parameters of the Right, so the whole side the question is what if the allocation happens conditionally depending on The parameters past the function I Think for this checker this checker is quite simple. I don't think it looks at This kind of thing. I think it would report anyway, but I'm not quite sure that some other some other checkers We have like the ones from a memory safety. They try very hard to follow the The values as well So one way to I don't know if this checker does this already but with the way I We would do that would be to record two two specifications for that function one where some parameter if X equals zero as the precondition then it doesn't allocate and another if it's not then it allocates and then at the call Site you can see in which in which branch you are Yes Question The question is is the deep paid base deployment part of the open source code base or not So at the moment is mostly lives in our CI code and not in infer There's ongoing work about moving that logic inside in for itself. So not for now there is but There is part of it in info already, which is the part about comparing to reports and computing the lists of Pre-existing and fixed and introduced Buckets Yes How is it linked the two parts and that static analysis and the Isolation of Error for a garden the deep how much have a link in Inferred Do you envision that it would be possible to reuse the deep analysis part for other static analysis too? so the the question is how How interval woven are the static analysis part and the diff analysis part and At the moment not at all we just running for once running for a second time and then we do some logic just on the JSON report So that's how it works So it can it works the same way for all our analysis because it just works on the final report It could be a separate project that works for other things as well Yes The Yes, so the question is That we report only on the files touching the diff and isn't that a terrible idea? For instance for libraries because you're breaking all the clients and you don't know it. Yes, that's a good point So do we have do we sometimes look at this so No, not at the moment We don't quite know how to so how we would surface these issues to developers or how it will run so Yep, so We're still figuring this out We're trying to surface all the bugs to developers for instance all the pre-existing bugs in the code base That's one way to do it, but that doesn't quite answer this question Yes, last question Which other static analysis tools do we use at Facebook I Think we use a range of static analysis tools, but I'm not sure exactly which at what on what part of the project We use We use yeah, we use clang analyzer as well on some parts of the code and Yeah, we use a bunch of of Static analyzers, I'm not quite sure which sorry Okay, thanks everyone