Cyclone By Example 15-213 Spring 2007
Aleksey Kliger
Computer Science Department Carnegie Mellon University
March 8, 2007
Aleksey Kliger (CMU) Cyclone By Example Mar 8 1 / 26 The Big Picture Outline
1 The Big Picture
2 Pointer Arithmetic
3 Tagged Unions And Not-NULL Pointers
4 Regions
Aleksey Kliger (CMU) Cyclone By Example Mar 8 2 / 26 The Big Picture From C to Cyclone
Theme 1 Rule out unsafe features of C 2 When possible, check some properties of a program at compile-time. 3 Otherwise, do a runtime check.
Aleksey Kliger (CMU) Cyclone By Example Mar 8 3 / 26 The Big Picture Unsafe Features of C Review of Tuesday’s Lecture
1 Pointer arithmetic 2 NULL pointer dereferences 3 Union types 4 Pointers to local variables 5 Casting to pointer types 6 Malloc/free 7 Symbol confusion during linking 8 Format string problems 9 Uninitialized Variables
Aleksey Kliger (CMU) Cyclone By Example Mar 8 4 / 26 The Big Picture Unsafe Features of C Review of Tuesday’s Lecture
1 Pointer arithmetic 2 NULL pointer dereferences 3 Union types 4 Pointers to local variables 5 Casting to pointer types 6 Malloc/free 7 Symbol confusion during linking 8 Format string problems 9 Uninitialized Variables
Aleksey Kliger (CMU) Cyclone By Example Mar 8 4 / 26 The Big Picture C vs Cyclone
C Cyclone 1 Pointer arithmetic 1 @fat pointers 2 NULL pointer dereferences 2 @notnull pointers or runtime checks 3 Union types 3 @tagged unions 4 Pointers to local variables 4 @region() annotations
Aleksey Kliger (CMU) Cyclone By Example Mar 8 5 / 26 Pointer Arithmetic Outline
1 The Big Picture
2 Pointer Arithmetic
3 Tagged Unions And Not-NULL Pointers
4 Regions
Aleksey Kliger (CMU) Cyclone By Example Mar 8 6 / 26 Pointer Arithmetic Pointer Arithmetic C version
Example (Singly-linked Example (Array to list) lists) list* array2list(int* A, int n) { struct List { list* l = NULL; int head; int i; struct List* tail; for (i = n-1; i >= 0; i--) { }; list* t = malloc (sizeof (list)); typedef t->head = A[i]; struct List t->tail = l; list; l = t; }
return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 7 / 26 Pointer Arithmetic Pointer Arithmetic C version
Example (Singly-linked Example (Array to list) lists) list* array2list(int* A, int n) { struct List { list* l = NULL; int head; int i; struct List* tail; for (i = n-1; i >= 0; i--) { }; list* t = malloc (sizeof (list)); typedef t->head = A[i]; struct List t->tail = l; list; l = t; }
return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 7 / 26 Pointer Arithmetic Array To List Illustration
Example (Array to list) list* array2list(int* A, int n) { list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
Example t->head = A[i]; int a[3] = t->tail = l; {7, 8, 9}; l = t; list* result = } array2list (a, 3); return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 8 / 26 Pointer Arithmetic Array To List Illustration
Example (Array to list) list* array2list(int* A, int n) { list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
Example t->head = A[i]; int a[3] = t->tail = l; {7, 8, 9}; l = t; list* result = } array2list (a, 3); return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 8 / 26 Pointer Arithmetic Array To List Illustration
Example (Array to list) list* array2list(int* A, int n) { list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
Example t->head = A[i]; int a[3] = t->tail = l; {7, 8, 9}; l = t; list* result = } array2list (a, 3); return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 8 / 26 Pointer Arithmetic Array To List Illustration
Example (Array to list) list* array2list(int* A, int n) { list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
Example t->head = A[i]; int a[3] = t->tail = l; {7, 8, 9}; l = t; list* result = } array2list (a, 3); return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 8 / 26 Pointer Arithmetic Array To List Illustration
Example (Array to list) list* array2list(int* A, int n) { list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
Example t->head = A[i]; int a[3] = t->tail = l; {7, 8, 9}; l = t; list* result = } array2list (a, 3); return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 8 / 26 Pointer Arithmetic Array To List Unsafe Aspects
Question Example (Array to list) What’s unsafe here? list* array2list(int* A, int n){ list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
t->head = A[i]; t->tail = l; l = t; }
return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 9 / 26 Pointer Arithmetic Array To List Unsafe Aspects
Question Example (Array to list) What’s unsafe here? list* array2list(int* A, int n){ list* l = NULL; int i; for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
t->head = A[i]; t->tail = l; l = t; }
return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 9 / 26 Pointer Arithmetic Array To List Cyclone Version
Example (Array to list) 1 Fat pointer list* array2list(int? A){ (int? A) list* l = NULL; 2 Number of int i; int n = numelts(A); elements for (i = n-1; i >= 0; i--) { numelts(A) list* t = malloc (sizeof (list));
3 Array bounds check t->head = A[i]; t->tail = l; l = t; } (int ? abbreviates int *@fat) return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 10 / 26 Pointer Arithmetic Array To List
Let’s compile it! [aleksey@tuna] cyclone -Wall -c array2list.cyc ***Warnings*** array2list.cyc:16: inserted bounds check at A[i] array2list.cyc:16: inserted null check **************
Often, Cyclone can eliminate bounds checks. Sometimes it can’t.
Aleksey Kliger (CMU) Cyclone By Example Mar 8 11 / 26 Pointer Arithmetic Array To List
Let’s compile it! [aleksey@tuna] cyclone -Wall -c array2list.cyc ***Warnings*** array2list.cyc:16: inserted bounds check at A[i] array2list.cyc:16: inserted null check **************
But why the null check?
Aleksey Kliger (CMU) Cyclone By Example Mar 8 11 / 26 Pointer Arithmetic Array To List @fat pointers can be null
Example (Array to list) list* array2list(int? A) { list* l = NULL; int i; int n = numelts(A);
If A were NULL, we for (i = n-1; i >= 0; i--) { would never get here, list* t = malloc (sizeof (list)); but Cyclone doesn’t know that. t->head = A[i]; t->tail = l; l = t; } return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 12 / 26 Pointer Arithmetic Array To List @fat pointers can be null
Example (Array to list) list* array2list(int? A) { list* l = NULL; Add our own NULL int i; int n = numelts(A); check (outside the if (!A) return NULL; loop). for (i = n-1; i >= 0; i--) { list* t = malloc (sizeof (list));
t->head = A[i]; t->tail = l; l = t; } return l; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 12 / 26 Tagged Unions And Not-NULL Pointers Outline
1 The Big Picture
2 Pointer Arithmetic
3 Tagged Unions And Not-NULL Pointers
4 Regions
Aleksey Kliger (CMU) Cyclone By Example Mar 8 13 / 26 Tagged Unions And Not-NULL Pointers Zoology (From a gazelle’s perspective)
Example (Animals) Example (Count teeth) struct Herbivore {...}; int count_teeth(animal struct Carnivore { serengeti[], int numteeth; ... int n) { }; int total = 0; struct Animal { int i; int isCarnivore; union { for (i = 0; i < n; i++) { struct Herbivore* h; if (serengeti[i].isCarnivore) struct Carnivore* c; total += }; serengeti[i].c->numteeth; }; } typedef struct Animal return total; animal; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 14 / 26 Tagged Unions And Not-NULL Pointers Zoology (From a gazelle’s perspective)
Example (Animals) Example (Count teeth) struct Herbivore {...}; int count_teeth(animal struct Carnivore { serengeti[], int numteeth; ... int n) { }; int total = 0; struct Animal { int i; int isCarnivore; union { for (i = 0; i < n; i++) { struct Herbivore* h; if (serengeti[i].isCarnivore) struct Carnivore* c; total += }; serengeti[i].c->numteeth; }; } typedef struct Animal return total; animal; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 14 / 26 Tagged Unions And Not-NULL Pointers Zoology Unsafe features
Example (Count teeth) int count_teeth(animal serengeti[], int n){ int total = 0; int i;
for (i = 0; i < n; i++) { if (serengeti[i].isCarnivore) total += serengeti[i].c->numteeth; } return total; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 15 / 26 Tagged Unions And Not-NULL Pointers Zoology Unsafe features
Example (Count teeth) int count_teeth(animal serengeti[], int n){ 1 Arrays int total = 0; 2 Tag and union field int i; may be out of sync 3 Dereferencing a pointer for (i = 0; i < n; i++) { without checking for if (serengeti[i].isCarnivore) NULL total += serengeti[i].c->numteeth; } return total; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 15 / 26 Tagged Unions And Not-NULL Pointers Safe Zoology Use @tagged and @notnull
Example (Animals) struct Herbivore {...}; struct Carnivore { int numteeth; ... }; struct Animal { int isCarnivore; union { struct Herbivore* h; struct Carnivore* c; }; }; typedef struct Animal animal;
Aleksey Kliger (CMU) Cyclone By Example Mar 8 16 / 26 Tagged Unions And Not-NULL Pointers Safe Zoology Use @tagged and @notnull
Example (Animals) struct Herbivore {...}; 1 @tagged union: compiler knows the struct Carnivore { role of the tag in selecting between int numteeth; ... .h and .c }; 2 struct Carnivore @ is a pointer @tagged that must not be NULL. union Animal { Safe to dereference without a runtime check. struct Herbivore@ h; struct Carnivore@ c; (struct Carnivore @ is shorthand for }; struct Carnivore *@notnull) typedef union Animal animal;
Aleksey Kliger (CMU) Cyclone By Example Mar 8 16 / 26 Tagged Unions And Not-NULL Pointers Safe Zoology Use tagcheck
Example (Animals) Example (Count Teeth) struct Herbivore {...}; int count_teeth(animal ? struct Carnivore { serengeti) { int numteeth; ... int total = 0; }; int i; @tagged int n = numelts(serengeti); union Animal { if (!serengeti) return 0; for (i = 0; i < n; i++) { struct Herbivore@ h; if (tagcheck(serengeti[i].c)) struct Carnivore@ c; total += serengeti[i].c->numteeth; }; } typedef union Animal return total; animal; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 17 / 26 Tagged Unions And Not-NULL Pointers Compiling Zoology
Compile [aleksey@tuna] cyclone -Wall -c zoology.cyc
Success! (Note that Cyclone even figured out that it is safe to remove the array bounds check)
Aleksey Kliger (CMU) Cyclone By Example Mar 8 18 / 26 Regions Outline
1 The Big Picture
2 Pointer Arithmetic
3 Tagged Unions And Not-NULL Pointers
4 Regions
Aleksey Kliger (CMU) Cyclone By Example Mar 8 19 / 26 Regions Append a list to the end of another
Example void append_to_end (list@ last, list* l2) { last->tail = l2; }
Aleksey Kliger (CMU) Cyclone By Example Mar 8 20 / 26 Regions That all seems safe...
Compile [aleksey@tuna]$ cyclone -Wall -c append-to-end.cyc
append-to-end.cyc:12: type mismatch: struct List * != list *‘GE1 ‘GE1 and ‘H are not compatible.
COMPILATION FAILED! What in the world is ‘GE1?
Aleksey Kliger (CMU) Cyclone By Example Mar 8 21 / 26 Regions It’s a pointer to where? Example ... list local; local.head = 12; local.tail = NULL; append_to_end(last, &local); ... return ...
Aleksey Kliger (CMU) Cyclone By Example Mar 8 22 / 26 Regions It’s a pointer to where? Example ... list local; local.head = 12; local.tail = NULL; append_to_end(last, &local); ... return ...
Aleksey Kliger (CMU) Cyclone By Example Mar 8 22 / 26 Regions Regions
Every pointer has a region: By default: @region(‘H) pointer to the Function arguments point to heap an arbitrary region @region(‘func name) pointer Function returns point to to the stack frame the heap of func name() Pointers mentioned in @regions(‘regionvar ) structs, unions, and pointer to some typedefs point to the heap arbitrary region
Aleksey Kliger (CMU) Cyclone By Example Mar 8 23 / 26 Regions Error Message Revisited
Example void append_to_end (list@ last, list*‘reg_var l2) { last->tail = l2; }
Compile [aleksey@tuna]$ cyclone -Wall -c append-to-end.cyc
append-to-end.cyc:12: type mismatch: struct List * != list *‘reg_var ‘reg_var and ‘H are not compatible.
COMPILATION FAILED!
Aleksey Kliger (CMU) Cyclone By Example Mar 8 24 / 26 Regions Typical solution to region errors Put it on the heap
Example void append_to_end (list@ last, list*‘H l2) { last->tail = l2; }
Compile [aleksey@tuna]$ cyclone -Wall -c append-to-end.cyc
Success!
Aleksey Kliger (CMU) Cyclone By Example Mar 8 25 / 26 Summary Summary
Pointer Arithmetic Fat pointers and bounds checks Unions of pointers Tagged unions Dereferencing NULL Not-NULL pointers and runitme checks Returning pointers to local variables Region annotations Cyclone defaults sometimes too generous: lead to errors. Add ‘H Questions?
The Cyclone homepage is http://cyclone.thelanguage.org
Aleksey Kliger (CMU) Cyclone By Example Mar 8 26 / 26