PolySync / static-analysis-argumentation

Argumentation around the efficacy of static analysis tooling for C and the Rust compiler in catching software errors pre-runtime.
GNU General Public License v2.0
11 stars 4 forks source link

PCLint and Coverity results with white paper examples #2

Open ubercool2 opened 6 years ago

ubercool2 commented 6 years ago

First off, hats of to PolySync team for challenging safety standards and putting safety first. We all need this in AD industry.

Here is our tests with your examples from the paper:

  1. Mutable Aliasing

    • PCLint: no detection
    • Coverity: no detection
  2. Breaking the const Promise

    • PCLint: correct detection

      2: [src/ps_constant.c:22]: (note: 9005) cast drops const qualifier [MISRA 2012 Rule 11.8, required]

    • Coverity: correct detection

      src/ps_constant.c:22: The object pointer expression "alias_to_alias" of type "example_s const * const *" is cast to type "example_s **".

  3. Unreliable Pattern Matching

    • PCLint: partial, incomplete detection
      2: [src/ps_pattern.c:54]: (info: 713) implicit conversion (call) from 'action_e' to 'int32_t' (aka 'int')
      2: [src/ps_pattern.c:54]: (note: 9034) cannot assign 'enum (action_e)' to different essential type 
      'signed32' [MISRA 2012 Rule 10.3, required]
      2: [src/ps_pattern.c:54]: (warning: 641) implicit conversion of enum 'action_e' to integral type 'int32_t' 
      (aka 'int')
      2: [src/ps_pattern.c:17]: (info: 749) local enumeration constant 'APPLY_BRAKE' not referenced
    • Coverity: partial, incomplete detection
  src/ps_pattern.c:54: Implicit conversion of "pattern" from essential type anonymous enum to different or narrower essential type signed 32-bit int.
  1. Data Races
    • PCLint: no detection
    • Coverity: no detection

Some of the problems can be avoided when using C++:

  1. Mutable Aliasing:
    Don't use pointers. 99% of points can be replaced by references which are much safer. Pointers allow encoding optionality which is very often not desired. Use constructs like gsl::not_null from https://github.com/Microsoft/GSL/blob/master/include/gsl/pointers.

  2. Breaking the ‘const‘ Promise
    Avoiding c-style casts also solves this problem as const cast in C++ is easy to detect.

  3. Unreliable Pattern Matching C++ has typed enums which solve this problem.

  4. Data Races
    Again, do not use pointers.

We feel that Rust has a lot of promise, but comparing it to C in the kinds of safety critical applications, and arguing that Rust is a better solution now, is at least hard. We see an issue of maturity. The maturity is lacking for us in three ways: first fundamental features and libraries are still missing or in development (maturity of the ecosystem), second it has not been (as far as we know) used in real-time software where determinism is required (We believe Rust still liberally uses dynamic memory allocation, so memory fragmentation is a thing), and third Rust still depends on lots of C/C++ code which can be unsafe if not used properly in the Rust bindings.

shnewto commented 6 years ago

Hi there @ubercool2 , I really appreciate you providing these results, thank you. I'll keep this issue open for visibility.

pittma commented 6 years ago

Full disclosure: I am also a PolySync employee.

Here are a few thoughts that arrived in my head given your conclusion @ubercool2:

  1. I'd love to know more specifically about what features and/or libraries which Rust is lacking. My rationale here is that I believe it'd be productive to exercise these deficiencies because we (and the greater Rust community, I'm sure) are interested how to help in this area!

  2. In regards to RTOS-y things: In the case of the memory striation example you shared, you might be able to take that problem on by implementing your own allocator, as there's a hook and a trait one can implement to roll their own. Other than that, Rust's compilation pipeline only differs from say, Clang, in its frontend. What are some of your other concerns here?

  3. Does it? Or are you referring to FFI use cases? I can imagine (but I can't say concretely) that there are some syscall shaped things that may still use C, but even that, Rust has its own libc implementation.

    1. This is kind of tangential, but if your concerns from # 3 above are around FFI, take a look at the RustBelt paper. Its authors had a number of wonderful outcomes WRT formalizing (a subset) of Rust's type and borrow system, but they also created a framework for verifying the semantics of things that happen inside unsafe blocks!

      This is the shape of thing that we get excited about with Rust, because when we can't benefit from the guarantees the compiler has blessed us with, we have other options to assert that these concessions are not compromising safety.