- Concepts of Programming Languages

Safety

Instructor:

Learning Objectives

How do we make sure that we access memory correctly?

  • Identify and describe memory access through pointers
  • Identify and describe examples of unsafe behavior in C

Types in C

What do you make of this program?

  1. int main() {
  2. int *p = (int*) malloc (sizeof(int));
  3. *p = 2123456789;
  4. printf ("(float)*p = %f\n", (float)*p); /* loss of precision */
  5. printf ("*(float*)p = %f\n", *(float*)p); /* rubbish */
  6. int i = 2;
  7. char s[] = "three";
  8. printf ("i*s = %ld\n", i*(long)s);
  9. }
  1. $ clang -m32 typing-00.c && ./a.out
  2. (float)*p = 2123456768.000000
  3. *(float*)p = 96621069057346178268049192388430659584.000000
  4. i*s = -1047484

Unsafe Memory Access

  • Memory location contains data written at a given type (such as character array)
  • The same memory location is read without permission or interpreted at an incompatible type (such as int)
  • This is an unsafe access
  • Scala prevents unsafe access by throwing an exception
    1. val x : Int = "Hello".asInstanceOf[Int]
    2. java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

Array Bounds

What do you make of the following program?

  1. int main () {
  2. float f = 10;
  3. int a[] = { 10 };
  4. short i = 10;
  5. printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
  6. a[-1] = 2123456789; printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
  7. a[1] = 2123456789; printf ("f=%f, a[0]=%d i=%d\n", f, a[0], i);
  8. }
  1. $ clang -m32 typing-03.c && ./a.out
  2. f=10.000000, a[0]=10 i=10
  3. f=10.000000, a[0]=10 i=32401
  4. f=96621069057346178268049192388430659584.000000, a[0]=10 i=32401

Pointer Aliasing on the Stack

  1. int main() {
  2. int x = 2123456789;
  3. double y = x;
  4. printf ("x=%d, y=%f\n", x, y);
  5. double *p = &x;
  6. double z = *p;
  7. printf ("x=%d, z=%f\n", x, z);
  8. }
  1. $ gcc typing-06.c && ./a.out
  2. x=2123456789, y=2123456789.000000
  3. x=2123456789, z=38685644468023060038942720.000000

Pointer Aliasing on the Heap

  1. int main() {
  2. int* ip = (int*) malloc (sizeof(int));
  3. *ip = 10;
  4. free(ip);
  5. float* fp = (float*) malloc (sizeof(float));
  6. *fp = 10;
  7. printf ("*fp=%f, *ip=%d\n", *fp, *ip);
  8. printf (" fp=%p, ip=%p\n", fp, ip);
  9. }
  1. $ gcc typing-07.c && ./a.out
  2. *fp=10.000000, *ip=1092616192
  3. fp=0x1063010, ip=0x1063010

Unsafety and Security

Safe Languages: Java and Scala

To be safe, Java and Scala do the following

  • Disallow pointers into the stack
  • Disallow pointer arithmetic
  • Disallow explicit free
  • Check array bounds
  • Check type casts

Bounds Checking

Java

  1. Object[] bs = new Object[4];
  2. Object b = bs[-1];

Scala

  1. val bs = Array(1, 2, 3, 4)
  2. val b = bs(-1)
  • Out-of-bounds access raises an exception
    1. java.lang.ArrayIndexOutOfBoundsException: -1

Checked Casts

Java

  1. class A { int x; }
  2. class B extends A { float y; }
  3. class C extends A { char c; }
  4. static void f (B b) {
  5. A a = b; /* upcast always safe */
  6. }
  7. static void g (A a) {
  8. B b = (B) a; /* downcast must be checked */
  9. }
  10. f (new B());
  11. g (new C());
  • Scala
    1. class A(val x: Int)
    2. class B(val y: Float) extends A(1)
    3. class C(val c: Char) extends A(2)
    4. /* upcast always safe */
    5. def f (b: B) = { val a: A = b }
    6. /* downcast must be checked */
    7. def g (a: A) = { val b: B = a.asInstanceOf[B] }
    8. f (new B(2.0))
    9. g (new C('c'))
  1. java.lang.ClassCastException: C cannot be cast to B

Summary

  • Traditional systems languages are purposefully unsafe: Assembly, C, C++, Objective-C, C#-unmanaged, ...
  • Recent application languages are meant to be safe: Java, Scheme, Javascript, Python, C#-managed, ...
  • Recent systems languages attempt to isolate the unsafe bits: Rust, Go
  • Even in safe languages, the overuse of dynamic checks allows program flaws to make it into production
  • Overuse of null is considered a billion dollar mistake

40min

Use illustrations of memory on the board: int vs. fixed-point numbers