Skip to content

Commit

Permalink
refactoring names
Browse files Browse the repository at this point in the history
  • Loading branch information
thradams committed Mar 5, 2024
1 parent 70979b9 commit e322139
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 231 deletions.
89 changes: 41 additions & 48 deletions ownership_proposal.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# New qualifiers to enable checked lifetime contracts
# New qualifiers to enable lifetime memory safety

## Abstract

This proposal introduces new qualifiers to improve safety regarding the misuse of object lifetimes.
These new qualifiers add contracts that can be checked at compile time, but requiring flow analysis.
These new qualifiers creates contracts that can be checked at compile time.


## Introduction, Motivation
Expand All @@ -24,48 +24,33 @@ int main()

## Design

We introduce several qualifiers called ownership qualifiers.
We introduce several qualifiers to established new compile time contracts.

Just like `const` has in its basic principle avoid the object to be modified,
ownership qualifiers have principles in mind and all the principles serve to keep the objective.
Principles for lifetime contracts

Principles:
1. Each object has only one owner
2. Ownership can be transferred between owners
3. Before the end of its lifetime, the owner object must transfer the ownership of the object it owns.
4. The object referenced by non-owner (view) must have a valid lifetime.

1 - Each object has only one owner
2 - Ownership can be transferred between owners
3 - Before the end of its lifetime, the owner object must transfer the ownership of the object it owns.
4 - The object referenced by non-owner (view) must have a valid lifetime.

This principles serve as constrains to archive safety and avoid undefined behavior.

This part is from C23 standard.

"
6.2.4 Storage durations of objects
...If an object is referred to outside of its lifetime, the behavior is undefined.
If a pointer value is used in an evaluation after the object the pointer points to (or just past) reaches
the end of its lifetime, the behavior is undefined.
The representation of a pointer object becomes indeterminate when the object the pointer points to
(or just past) reaches the end of its lifetime.
"

## Ownership qualifiers

`_Owner` indicates that an object works as a reference to another object,
managing its lifetime as its unique owner. When _Owner qualifier are aplied to pointes
it means the pointer is the owner of two objects.
`_Owner` An owner qualified object is an object referencing another object and managing its lifetime. When _Owner qualifier is applied to pointer it means the pointer if the owner of the memory and the object.

`_Obj_owner` It is a qualifier for pointer that indicates the pointer is the owner
`_Obj_owner` It is a qualifier for pointer only that indicates the pointer is the owner
of the pointed object but it not owner of the memory.

`_View` qualifier is the opposite of _Owner.
`_View` Qualifier is the opposite of _Owner.

`_Opt` Used in function arguments to indicate the argument can be uninitialized.
`_Opt` Used in function arguments, for pointer only, to indicate the argument can be null.

`_Out` Indicates the object is uninitialized


## Constrains that don't require flow analysis
## Constrains

The result of a function returning a owner object cannot be discarded.
- The result of a function returning a owner object cannot be discarded.

```c
int* _Owner f();
Expand All @@ -74,7 +59,7 @@ int main(){
}
```

The result of a function returning a owner object must be transferred to another owner object.
- The result of a function returning a owner object must be transferred to another owner object.

```c
int* f();
Expand All @@ -90,23 +75,14 @@ int main(){
}
```

The result of a function returning a owner object cannot be returned as non-owner.
Except:
- If the storage duration is static, or function pointer
- The result of a function returning a owner object cannot be returned as non-owner, except if the storage duration is static, or function or if returns an argument.

```c
```c
_Owner int i;
int* f()
{
return i; //ok
int* f() {
return i; //ok
}
```

- If the owner returned is a function argument.

```c
int* f(int * _Owner p)
{
int* f(int * _Owner p) {
return p;
}
```
Expand All @@ -123,10 +99,27 @@ int* f()
}
```

- The result of a function returning an owner object cannot be passed to a view parameter.

```c
void free(void* p);
void * _Owner make();
int main()
{
free(make()); //error
}
```
- A _Obj_Owner qualified object can assigned to owner object.


```c
void delete(void* _Owner p);
void destroy(void* _Obj_owner p)
{
delete(p); //error
}
```

# Semantics with flow analysis
- Assignment of owner objects move the ownership.
- Assignment of non-owner to owner creates a view reference
Expand Down
4 changes: 2 additions & 2 deletions src/expressions.c
Original file line number Diff line number Diff line change
Expand Up @@ -2612,11 +2612,11 @@ struct expression* owner cast_expression(struct parser_ctx* ctx)
if (type_is_pointer(&p_expression_node->left->type))
{
//(int*) malloc(1)
compiler_diagnostic_message(W_DISCARDING_OWNER, ctx, p_expression_node->first_token, "discarding owner pointer");
compiler_diagnostic_message(W_OWNERSHIP_DISCARDING_OWNER, ctx, p_expression_node->first_token, "discarding owner pointer");
}
else
{
compiler_diagnostic_message(W_DISCARDING_OWNER, ctx, p_expression_node->first_token, "discarding owner");
compiler_diagnostic_message(W_OWNERSHIP_DISCARDING_OWNER, ctx, p_expression_node->first_token, "discarding owner");
}
}
}
Expand Down
16 changes: 4 additions & 12 deletions src/file.c
Original file line number Diff line number Diff line change
@@ -1,13 +1,5 @@
void free(void* _Owner p);
struct X
void delete(void* _Owner p);
void destroy(void* _Obj_owner p)
{
int i;
void* _Owner p;
};
void f(const struct X* p);
int main()
{
struct X x = { 0 };
f(x);
static_state(x.p, "null");
}
delete(p);
}
18 changes: 9 additions & 9 deletions src/flow_visit.c
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,7 @@ static int compare_function_arguments2(struct parser_ctx* ctx,
if (p_argument_object2 &&
p_argument_object2->state & OBJECT_STATE_NULL)
{
compiler_diagnostic_message(W_ANALIZER_MAYBE_NULL_TO_NON_OPT_ARGUMENT,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_MAYBE_NULL_TO_NON_OPT_ARG,
ctx,
p_current_argument->expression->first_token,
"pointer can be null, but the parameter is not optional");
Expand Down Expand Up @@ -1330,13 +1330,13 @@ static void check_uninitialized(struct flow_visit_ctx* ctx, struct expression* p
p_expression->declarator &&
p_expression->declarator->name)
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->first_token, "using a uninitialized object '%s'", p_expression->declarator->name->lexeme);
}
else
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->first_token, "using a uninitialized object");
}
Expand All @@ -1345,13 +1345,13 @@ static void check_uninitialized(struct flow_visit_ctx* ctx, struct expression* p
{
if (p_expression->declarator && p_expression->declarator->name)
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->declarator->name, "object '%s' can be uninitialized ", p_expression->declarator->name->lexeme);
}
else
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->first_token, "maybe using a uninitialized object");
}
Expand Down Expand Up @@ -1541,13 +1541,13 @@ static void flow_visit_expression(struct flow_visit_ctx* ctx, struct expression*
{
if (p_object && p_object->state == OBJECT_STATE_UNINITIALIZED)
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->right->first_token, "using a uninitialized object");
}
else if (p_object && p_object->state & OBJECT_STATE_UNINITIALIZED)
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->right->first_token, "maybe using a uninitialized object");
}
Expand Down Expand Up @@ -1580,7 +1580,7 @@ static void flow_visit_expression(struct flow_visit_ctx* ctx, struct expression*
{
if (!ctx->expression_is_not_evaluated)
{
compiler_diagnostic_message(W_ANALYZER_UNINITIALIZED,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_UNINITIALIZED,
ctx->ctx,
p_expression->right->first_token, "using a uninitialized object");
}
Expand All @@ -1597,7 +1597,7 @@ static void flow_visit_expression(struct flow_visit_ctx* ctx, struct expression*
if (p_object && !(p_object->state & OBJECT_STATE_NOT_NULL))
{

compiler_diagnostic_message(W_ANALYZER_NULL_DEREFERENCE,
compiler_diagnostic_message(W_OWNERSHIP_FLOW_NULL_DEREFERENCE,
ctx->ctx,
p_expression->right->first_token, "dereference a NULL object");
}
Expand Down
Loading

0 comments on commit e322139

Please sign in to comment.