23. Designing Asynchronous APIs
Let API user specify callback queue
DeepThought.asyncComputeAnswer(to: theQuestion) { reply in
…
}
24. Designing Asynchronous APIs
Let API user specify callback queue
DeepThought.asyncComputeAnswer(to: theQuestion, completionQueue: queue) { reply in
…
}
25. Address Sanitizer
• Detects use-after-scope
• Detects use-after-return (opt-in)
• Compatible with Malloc Scribble
Finding Memory Issues
Security critical bugs
• Use-after-free and buffer overflows
Diagnoses hard-to-reproduce crashes
Advanced Debugging and the Address Sanitizer WWDC 2015
26. Use of out of scope stack memory
// Use of Stack Memory Out of Scope
int *integer_pointer = NULL;
if (is_some_condition_true()) {
int value = calculate_value();
integer_pointer = &value;
}
*integer_pointer = 42;
27. // Use of Stack Memory after Return
int *returns_address_of_stack() {
int a = 42;
return &a;
}
int *integer_pointer = returns_address_of_stack();
*integer_pointer = 43;
28.
29. Thread Sanitizer
• Race on collections
• Swift access races
What is Thread Sanitizer
Multithreading issues
Finds races even if they did not manifest
64-bit macOS, 64-bit simulators
Thread Sanitizer and Static Analysis WWDC 2016
30. // Thread 1
eventLog.log(source: networkingSubsystem, message: "Download finished")
// Thread 2
eventLog.log(source: databaseSubsystem, message: "Query complete")
Thread 2: Data race in EventLog.log(source:message:)
// Swift Data Race Example
class EventLog {
private var lastEventSource: LogSource?
func log(source: LogSource, message: String) {
print(message)
lastEventSource = source
}
}
31. // Use DispatchQueue to Synchronize Access
class EventLog {
private var lastEventSource: LogSource?
private var queue = DispatchQueue(label: "com.example.EventLog.queue")
func log(source: LogSource, message: String) {
queue.async {
print(message)
lastEventSource = source
}
}
}
32. // Swift Access Race with Mutating Methods
struct BluePoliceBoxLocation {
private var x, y, z: Int
private var time: Int
}
mutating func teleport(toPlanet: String) { … }
mutating func fly(toCity: String) { … }
mutating func travelToEndOfTime() { … }
Thread 2: Swift access race
Thread 1: Previous access
// Thread 1
location.teleport(toPlanet: "Mars")
// Thread 2
location.travelToEndOfTime()
changes x, y, z
changes time
38. Null pointer returned from function declared to never return null
// Nonnull Return Value Violation
@implementation SolarSystem
+ (nonnull NSDictionary *)planetMoons {
return @{@"Earth": @[@"Moon"],
@"Mars" : @[@"Phobos", @"Deimos"],
// …
};
}
- (nonnull NSArray *)moonsOfPlanet:(nonnull NSString *)planet {
return [[self class] planetMoons][planet];
}
@end
// Find the biggest moon for each planet
NSMutableArray *biggestMoons = [NSMutableArray new];
[biggestMoons addObject:[solarSystem moonsOfPlanet:@"Pluto"][0]];
Nonnull Return Value Violation
39. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 1
Dead Code
Elimination
Redundant Null
Check Elimination
Redundant Null
Check Elimination
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
*P = 4;
} Keep the brace in MM
if (P == NULL)
return;
Dead Code
Elimination
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Keep the closing brace MM
Compiler Optimization
40. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 1
Dead Code
Elimination
Redundant Null
Check Elimination
Redundant Null
Check Elimination
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
*P = 4;
} Keep the brace in MM
Dead Code
Elimination
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Keep the closing brace MM
Compiler Optimization 1
41. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 1
Dead Code
Elimination
Redundant Null
Check Elimination
Dead Code
Elimination
int unused = *P;
void contains_null_check(int *P) {
…Hidden text for MM
*P = 4;
} Keep closing brace in MM
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
*P = 4;
} Keep the brace in MM
Compiler Optimization 1
42. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 1
Dead Code
Elimination
Redundant Null
Check Elimination
Dead Code
Elimination
void contains_null_check(int *P) {
…Hidden text for MM
*P = 4;
} Keep closing brace in MM
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
*P = 4;
} Keep the brace in MM
Compiler Optimization 1
43. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 2
Redundant Null
Check Elimination
Dead Code
Elimination
Dead Code
Elimination
void contains_null_check(int *P) {
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Please keep the brace MM
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Keep brace during MM
int unused = *P;
Compiler Optimization 2
44. Compiler 2
Source code
.c, .m, .cpp, .mm
Object file
.o
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 2
Redundant Null
Check Elimination
Dead Code
Elimination
Dead Code
Elimination
void contains_null_check(int *P) {
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Please keep the brace MM
void contains_null_check(int *P) {
int unused = *P;
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Keep brace during MM
Compiler Optimization 2
45. Source code
.c, .m, .cpp, .mm
Object file
.o
Compiler 2
Let’s Experiment: A Very Simple Optimization Pipeline
Compiler 2
Redundant Null
Check Elimination
Dead Code
Elimination
Redundant Null
Check Elimination
void contains_null_check(int *P) {
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Please keep me MM!
void contains_null_check(int *P) {
…Hidden text for MM
if (P == NULL)
return;
*P = 4;
} Please keep the brace MM
Compiler Optimization 2
46. Let’s Experiment: A Very Simple Optimization Pipeline
A surprising result
void contains_null_check(int *P) {
int unused = *P;
…
if (P == NULL)
return;
*P = 4;
} Keep brace during MM
Compiler 1
void contains_null_check(int *P) {
…
*P = 4;
} Keep closing brace in MM
void contains_null_check(int *P) {
…
if (P == NULL)
return;
*P = 4;
}
void contains_null_check(int *P) {
int unused = *P;
…
if (P == NULL)
return;
*P = 4;
} Keep brace during MM
Compiler 2
Compiler Optimization
47. Using Runtime Tools Effectively
• Exercise more code
• Use the tools together
49. What's New in LLVM
• API Availability Checking for Objective-C
• Static Analyzer Checks
• New Warnings
• C++ Refactoring & Features from C++17
• Link-Time Optimization (LTO)
• API Availability Checking for Objective-C
• Static Analyzer Checks
• New Warnings
• C++ Refactoring & Features from C++17
• Link-Time Optimization (LTO)
51. API Availability Checking in Objective-C
if (@available(iOS 11,x*)) {
r = [VNDetectFaceRectanglesRequest new];
if ([handler performRequests:@[r] error:&error]) {
// Draw rectangles
}
} else {
// Fall back when API not available
}
Compiler warns about unguarded uses of new API
Use @available to query API availability at run time
API Availability Checking for Objective-C
52. Convenient to write entire methods with limited availability
@interface MyAlbumController : UIViewController
- (void)showFaces
@end
API_AVAILABILITY(ios(11.0));
Factor out Code with API_AVAILABILITY()
Convenient to write entire methods with limited availability
@interface MyAlbumController : UIViewController
- (void)showFaces
@end
API_AVAILABILITY(ios(11.0))
;
Can apply to entire classes
Factor out Code with API_AVAILABILITY()
53. API Availability Checking in C/C++
Use __builtin_available to check availability at runtime
if (__builtin_available(iOS 11, macOS 10.13, *)) {
CFNewAPIOniOS11();
}
54. API Availability Checking in C/C++
Use __builtin_available to check availability at runtime
Include <os/availability.h> for the API_AVAILABILITY macro
#include <os/availability.h>
void myFunctionForiOS11OrNewer(int i) API_AVAILABILITY(ios(11.0), macos(10.13));
55. Do Not Compare Number Objects to Scalars
Comparing NSNumber pointer value to 0 checks for nil – not zero number
@property NSNumber *photoCount;
- (BOOL)hasPhotos {
}
Comparing pointer value to a scalar integer valuereturn self.photoCount > 0;
Do Not Auto-Synthesize NSMutable copy Properties
Setter calls -copy, which yields an immutable copy
- (void)replaceWithStockPhoto:(NSImage *)stockPhoto {
self.photos = [NSMutableArray<NSImage *> new];
[self.photos addObject:stockPhoto];
}
-[__NSArray0 addObject:]: unrecognized selector sent to instance
@property (copy) NSMutableArray<NSImage *> *photos;
Static Analyzer Checks
Run Analyzer on Your Code!
Supports Objective-C, C, C++
Analyze during build