You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.7 KiB

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:

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

-(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:

-(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

  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.

If you are unsure whether or not foo() will return null , 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:

  // 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.

If you are absolutely sure that foo() will not be null , 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.