No Littering Tamu
No Littering Tamu
No Littering Tamu
Bjarne Stroustrup
Morgan Stanley
Columbia University, Texas A&M University
www.stroustrup.com
The big question
• “What is good modern C++?”
• Many people want to write ”Modern C++”
• Guidelines project
• https://github.com/isocpp/CppCoreGuidelines
• Produce a useful answer
• Enable many people to use that answer
• For most programmers, not just language experts
• Please help!
Stroustrup - Guidelines - CppCon'15 3
Overview
• Pointer problems
• Memory corruption
• Resource leaks
• Expensive run-time support
• Complicated code
• The solution
• Eliminate dangling pointers
• Eliminate resource leaks
• Library support for range checking and nullptr checking
• An object can be
• on stack (automatically freed)
• on free store (must be freed)
• n static store (must never be freed)
• in another object
No littering - Stroustrup - TAMU - March'16 7
Resource management can be messy
Thread
id Lock id Lock id
Map key
• Pointers can
• point outside an object (range error)
• be a nullptr ( don’t dereference)
• be unititialized (don’t dereference)
void g()
{
X* q = new X; // looks innocent enough
f(q);
// … do a lot of work here …
q->use(); // Ouch! Read/scramble random memory
} No littering - Stroustrup - TAMU - March'16 16
Dangling pointers
• We must eliminate dangling pointers
• Or type safety is compromised
• Or memory safety is compromised
• Or resource safety is compromised
• Eliminated by a combination of rules
• Distinguish owners from non-owners
• Assume raw pointers to be non-owners
• Catch every attempt for a pointer to “escape” into a scope
enclosing its owner’s scope
• return, throw, out-parameters, long-lived containers, …
• Something that holds an owner is an owner
• E.g. vector<owner<int*>>, owner<int*>[], …
Call stack
Object
Object
pointer pointer
pointer owner
owner
• For an object on the free store the owner is a pointer
• For a scoped object the owner is the scope
pointer • For a member object the owner is the enclosing object
No littering - Stroustrup - TAMU - March'16 18
Dangling pointers
• Ensure that no pointer outlives the object it points to
void f(X* p)
{
// …
delete p; // bad: delete non-owner
}
void g()
{
X* q = new X; // bad: assign object to non-owner
f(q);
// … do a lot of work here …
q->use(); // Make sure we never get here
} No littering - Stroustrup - TAMU - March'16 19
How do we represent ownership?
• High-level: Use an ownership abstraction
• This is simple and preferred
• E.g., unique_ptr, shared_ptr, vector, and map
• Low-level: mark owning pointers owner
• An owner must be deleted or passed to another owner
• A non-owner may not be deleted
• This is essential in places but does not scale
• Applies to both pointers and references
• A static analysis tool can tell us where our code mishandles ownership
No littering - Stroustrup - TAMU - March'16 23
A cocktail of techniques
• Not a single neat miracle cure
• Rules (from the “Core C++ Guidelines)
• Statically enforced
• Libraries (STL, GSL)
• So that we don’t have to directly use the messy parts of C++
• Reliance on the type system
• The compiler is your friend
• Static analysis
• Essentially to extend the type system
int* f(int* p)
{
int x = 4;
return &x; // No! would point to destroyed stack frame
return new int{7}; // OK (sort of): doesn’t dangle, should return an owner<int*>
return p; // OK: came from caller
}
• Concurrency
• Keep threads alive with scoping or shared_ptr
• Apply the usual rules for a thread’s stack
• Threat another thread as just another object (it is).
No littering - Stroustrup - TAMU - March'16 27
Other problems
• Other ways of breaking the type system
• Unions: use variant
• Casts: don’t use them
• …
• Other ways of misusing pointers
• Range errors: use span<T>
• nullptr dereferencing: use not_null<T>
• Wasteful ways of addressing pointer problems
• Misuse of smart pointers
•…
• “Just test everywhere at run time” is not an acceptable answer
• We want comprehensive guidelines
No littering - Stroustrup - TAMU - March'16 28
GSL – span<T>
• Common interface style
• major source of bugs
void f(int* p, int n) // what is n? (How would a tool know?)
{
p[7] = 9; // OK?
for (int i=0; i<n; ++i) p[i] = 7; // OK?
}
• Better
void f(span<int> a)
{
a[7] = 9; // OK? Checkable against a.size()
for (int& x : a) x = 7; // OK
}