correctcomputation / checkedc-clang

This is the primary development repository for 3C, a tool for automatically converting legacy C code to the Checked C extension of C, which aims to enforce spatial memory safety. This repository is a fork of Checked C's.
14 stars 5 forks source link

Wierd cast when parameter is checked pointer to unchecked pointer #160

Closed john-h-kastner closed 4 years ago

john-h-kastner commented 4 years ago

Function arguments are cast to int** when the corresponding parameter is _Ptr<int*>. In the following example, the cast can be removed, and it will still compile.

OriginalConverted
void buz(int **a) {
  *a = (int*)1;
}

void test() {
  int *y;
  buz(&y);
}
void buz(_Ptr<int*> a) {
  *a = (int*)1;
}

void test() {
  int *y;
  buz(((int **)&y));
}

I don't think this has the same underlying issue as #134. The place to start looking is probably this line in GatherTool.cpp.

https://github.com/plum-umd/checkedc-clang/blob/85c92041bd1e058b6781fd9deaa8a0f629e58b8d/clang/lib/CConv/GatherTool.cpp#L36

It considers a parameter WILD if any of its atoms are wild, so a checked pointer to an unchecked pointer is WILD even though the outermost pointer is checked.

sroy4899 commented 4 years ago

A related and slightly more worrying brother of this issue, where a user defined unchecked cast causes the converted program not to compile.

OriginalConverted
void foo() { 
    int *a = (int*) 0;
    int **b = (int**) 0;
}
void foo() { 
    _Ptr a =  (int*) 0;
    _Ptr<_Ptr> b =  (int**) 0;
}

The converted code fails to compile with the following error message:

error: initializing '_Ptr<_Ptr<int>>' with an expression of incompatible type 'int **'
    _Ptr<_Ptr<int>> b =  (int**) 0;
mwhicks1 commented 4 years ago

Some notes: complex_expression.c and ptrint.c tests both fail because of this. Note that Shilpa's followup actually fails to compile; this is a bug, not a nicety. Can extend the map from source locations to constraint variables, and then set a constraint variable with a cast, so it can be rewritten (e.g., either dropped, or changed to a Checked C cast).

john-h-kastner commented 4 years ago

I found an instance of this issue that actually results in output that won't compile.

void c(int ***e) {}

void d() {
  int *b = 1;
  int **a = &b;
  c(&a);
}

converts to this

void c(_Ptr<_Ptr<int *>> e) {}

void d() {
  int *b = 1;
  _Ptr<int *> a =  &b;
  c(((int ***)&a));
}

which clang rejects

test.checked.c:6:5: error: passing 'int ***' to parameter of incompatible type '_Ptr<_Ptr<int *>>'
  c(((int ***)&a));

Removing the (int ***) cast fixes it.

john-h-kastner commented 4 years ago

Fixed by #257