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