Summary: Adding more info to Pulse webpage Reviewed By: jvillard Differential Revision: D26884576 fbshipit-source-id: a6f13757fmaster
parent
cba144b779
commit
c736015316
@ -0,0 +1,56 @@
|
|||||||
|
### What is Infer:Pulse?
|
||||||
|
Pulse is an interprocedural memory safety analysis. Pulse can detect, for instance, [Null dereferences](/docs/next/all-issue-types#nullptr_dereference) in Java. Errors are only reported when all conditions on the erroneous path are true regardless of input. Pulse should gradually replace the original [biabduction](/docs/next/checker-biabduction) analysis of Infer. An example of a Null dereference found by Pulse is given below.
|
||||||
|
|
||||||
|
```java
|
||||||
|
class Person {
|
||||||
|
Person emergencyContact;
|
||||||
|
String address;
|
||||||
|
|
||||||
|
Person getEmergencyContact() {
|
||||||
|
return this.emergencyContact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Registry {
|
||||||
|
void create() {
|
||||||
|
Person p = new Person();
|
||||||
|
Person c = p.getEmergencyContact();
|
||||||
|
// Null dereference here
|
||||||
|
System.out.println(c.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printContact(Person p) {
|
||||||
|
// No null dereference, as we don't know anything about `p`
|
||||||
|
System.out.println(p.getEmergencyContact().address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
How to run pulse for Java:
|
||||||
|
```bash
|
||||||
|
infer run --pulse -- javac Test.java
|
||||||
|
```
|
||||||
|
|
||||||
|
Pulse reports a Null dereference on this file on `create()`, as it tries to access the field `address` of object `c`, and `c` has value `null`. In contrast, Pulse gives no report for `printContact(Person p)`, as we cannot be sure that `p.getEmergencyContact()` will return `null`. Pulse then labels this error as latent and only reports if there is a call to `printContact(Person p)` satisfying the condition for Null dereference.
|
||||||
|
|
||||||
|
### Pulse x Nullsafe
|
||||||
|
|
||||||
|
[Nullsafe](/docs/next/checker-eradicate) is a type checker for `@Nullable` annotations for Java. Classes following the Nullsafe discipline are annotated with `@Nullsafe`.
|
||||||
|
|
||||||
|
Consider the classes `Person` and `Registry` from the previous example. Assuming that class `Person` is annotated with `@Nullsafe`. In this case, we also annotate `getEmergencyContact()` with `@Nullable`, to make explicit that this method can return the `null` value. There is still the risk that classes depending on `Person` have Null dereferences. In this case, Pulse would report a Null dereference on `Registry`. It could also be the case that class `Registry` is annotated with `@Nullsafe`. By default Pulse reports on `@Nullsafe` files too, see the `--pulse-nullsafe-report-npe` option (Facebook-specific: Pulse does not report on `@Nullsafe` files).
|
||||||
|
|
||||||
|
```java
|
||||||
|
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||||
|
class Person {
|
||||||
|
Person emergencyContact;
|
||||||
|
String address;
|
||||||
|
|
||||||
|
@Nullable Person getEmergencyContact() {
|
||||||
|
return this.emergencyContact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Registry {
|
||||||
|
... // Pulse reports here
|
||||||
|
}
|
||||||
|
```
|
@ -1 +1,96 @@
|
|||||||
|
|
||||||
|
Infer reports null dereference bugs in Java, C and Objective-C. The issue is
|
||||||
|
about a pointer that can be `null` and it is dereferenced. This leads to a crash
|
||||||
|
in all the above languages.
|
||||||
|
|
||||||
|
### Null dereference in Java
|
||||||
|
|
||||||
|
Many of Infer's reports of potential NPE's come from code of the form
|
||||||
|
|
||||||
|
```java
|
||||||
|
p = foo(); // foo() might return null
|
||||||
|
stuff();
|
||||||
|
p.goo(); // dereferencing p, potential NPE
|
||||||
|
```
|
||||||
|
|
||||||
|
If you see code of this form, then you have several options.
|
||||||
|
|
||||||
|
<b> If you are unsure whether or not foo() will return null </b>, you should
|
||||||
|
ideally i. Change the code to ensure that foo() can not return null ii. Add a
|
||||||
|
check for whether p is null, and do something other than dereferencing p when it
|
||||||
|
is null.
|
||||||
|
|
||||||
|
Sometimes, in case ii it is not obvious what you should do when p is null. One
|
||||||
|
possibility (a last option) is to throw an exception, failing early. This can be
|
||||||
|
done using checkNotNull as in the following code:
|
||||||
|
|
||||||
|
```java
|
||||||
|
// code idiom for failing early
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
//... intervening code
|
||||||
|
|
||||||
|
p = checkNotNull(foo()); // foo() might return null
|
||||||
|
stuff();
|
||||||
|
p.goo(); // dereferencing p, potential NPE
|
||||||
|
```
|
||||||
|
|
||||||
|
The call checkNotNull(foo()) will never return null; in case foo() returns null
|
||||||
|
it fails early by throwing an NPE.
|
||||||
|
|
||||||
|
<b> If you are absolutely sure that foo() will not be null </b>, then if you
|
||||||
|
land your diff this case will no longer be reported after your diff makes it to
|
||||||
|
master.
|
||||||
|
|
||||||
|
### Null dereference in C
|
||||||
|
|
||||||
|
Here is an example of an inter-procedural null dereference bug in C:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Person {
|
||||||
|
int age;
|
||||||
|
int height;
|
||||||
|
int weight;
|
||||||
|
};
|
||||||
|
int get_age(struct Person *who) {
|
||||||
|
return who->age;
|
||||||
|
}
|
||||||
|
int null_pointer_interproc() {
|
||||||
|
struct Person *joe = 0;
|
||||||
|
return get_age(joe);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Null dereference in Objective-C
|
||||||
|
|
||||||
|
In Objective-C, null dereferences are less common than in Java, but they still
|
||||||
|
happen and their cause can be hidden. In general, passing a message to nil does
|
||||||
|
not cause a crash and returns `nil`, but dereferencing a pointer directly does
|
||||||
|
cause a crash as well as calling a `nil` block.C
|
||||||
|
|
||||||
|
```objectivec
|
||||||
|
-(void) foo:(void (^)())callback {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) bar {
|
||||||
|
[self foo:nil]; //crash
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Moreover, there are functions from the libraries that do not allow `nil` to be
|
||||||
|
passed as argument. Here are some examples:
|
||||||
|
|
||||||
|
```objectivec
|
||||||
|
-(void) foo {
|
||||||
|
NSString *str = nil;
|
||||||
|
NSArray *animals = @[@"horse", str, @"dolphin"]; //crash
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) bar {
|
||||||
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); //can return NULL
|
||||||
|
...
|
||||||
|
CFRelease(colorSpace); //crashes if called with NULL
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -1,97 +0,0 @@
|
|||||||
Infer reports null dereference bugs in C, Objective-C and Java. The issue is
|
|
||||||
about a pointer that can be `null` and it is dereferenced. This leads to a crash
|
|
||||||
in all the above languages.
|
|
||||||
|
|
||||||
### Null dereference in C
|
|
||||||
|
|
||||||
Here is an example of an inter-procedural null dereference bug in C:
|
|
||||||
|
|
||||||
```c
|
|
||||||
struct Person {
|
|
||||||
int age;
|
|
||||||
int height;
|
|
||||||
int weight;
|
|
||||||
};
|
|
||||||
int get_age(struct Person *who) {
|
|
||||||
return who->age;
|
|
||||||
}
|
|
||||||
int null_pointer_interproc() {
|
|
||||||
struct Person *joe = 0;
|
|
||||||
return get_age(joe);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Null dereference in Objective-C
|
|
||||||
|
|
||||||
In Objective-C, null dereferences are less common than in Java, but they still
|
|
||||||
happen and their cause can be hidden. In general, passing a message to nil does
|
|
||||||
not cause a crash and returns `nil`, but dereferencing a pointer directly does
|
|
||||||
cause a crash as well as calling a `nil` block.C
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
-(void) foo:(void (^)())callback {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) bar {
|
|
||||||
[self foo:nil]; //crash
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Moreover, there are functions from the libraries that do not allow `nil` to be
|
|
||||||
passed as argument. Here are some examples:
|
|
||||||
|
|
||||||
```objectivec
|
|
||||||
-(void) foo {
|
|
||||||
NSString *str = nil;
|
|
||||||
NSArray *animals = @[@"horse", str, @"dolphin"]; //crash
|
|
||||||
}
|
|
||||||
|
|
||||||
-(void) bar {
|
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); //can return NULL
|
|
||||||
...
|
|
||||||
CFRelease(colorSpace); //crashes if called with NULL
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Null dereference in Java
|
|
||||||
|
|
||||||
Many of Infer's reports of potential NPE's come from code of the form
|
|
||||||
|
|
||||||
```java
|
|
||||||
p = foo(); // foo() might return null
|
|
||||||
stuff();
|
|
||||||
p.goo(); // dereferencing p, potential NPE
|
|
||||||
```
|
|
||||||
|
|
||||||
If you see code of this form, then you have several options.
|
|
||||||
|
|
||||||
<b> If you are unsure whether or not foo() will return null </b>, you should
|
|
||||||
ideally i. Change the code to ensure that foo() can not return null ii. Add a
|
|
||||||
check for whether p is null, and do something other than dereferencing p when it
|
|
||||||
is null.
|
|
||||||
|
|
||||||
Sometimes, in case ii it is not obvious what you should do when p is null. One
|
|
||||||
possibility (a last option) is to throw an exception, failing early. This can be
|
|
||||||
done using checkNotNull as in the following code:
|
|
||||||
|
|
||||||
```java
|
|
||||||
// code idiom for failing early
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
|
||||||
|
|
||||||
//... intervening code
|
|
||||||
|
|
||||||
p = checkNotNull(foo()); // foo() might return null
|
|
||||||
stuff();
|
|
||||||
p.goo(); // dereferencing p, potential NPE
|
|
||||||
```
|
|
||||||
|
|
||||||
The call checkNotNull(foo()) will never return null; in case foo() returns null
|
|
||||||
it fails early by throwing an NPE.
|
|
||||||
|
|
||||||
<b> If you are absolutely sure that foo() will not be null </b>, then if you
|
|
||||||
land your diff this case will no longer be reported after your diff makes it to
|
|
||||||
master. In the future we might include analysis directives (hey, analyzer, p is
|
|
||||||
not null!) like in Hack that tell the analyzer the information that you know,
|
|
||||||
but that is for later.
|
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
title: "Config Impact Analysis"
|
||||||
|
description: "[EXPERIMENTAL] Collects function that are called without config checks."
|
||||||
|
---
|
||||||
|
|
||||||
|
[EXPERIMENTAL] Collects function that are called without config checks.
|
||||||
|
|
||||||
|
Activate with `--config-impact-analysis`.
|
||||||
|
|
||||||
|
Supported languages:
|
||||||
|
- C/C++/ObjC: Experimental
|
||||||
|
- Java: Experimental
|
||||||
|
- C#/.Net: Experimental
|
||||||
|
|
||||||
|
This checker collects functions whose execution isn't gated by certain pre-defined gating functions. The set of gating functions is hardcoded and empty by default for now, so to use this checker, please modify the code directly in [FbGKInteraction.ml](https://github.com/facebook/infer/tree/master/infer/src/opensource).
|
||||||
|
|
||||||
|
## List of Issue Types
|
||||||
|
|
||||||
|
The following issue types are reported by this checker:
|
||||||
|
- [CONFIG_IMPACT](/docs/next/all-issue-types#config_impact)
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue