FStarLang / FStarLang/pal

Support `free(NULL)` and deallocation of nullable pointers

Open
#294 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Rust
Stars
11
Forks
1
Avg merge
2d 3h
Merged PRs (30d)
47

Description

PAL currently rejects two valid null-deallocation patterns: freeing `NULL` directly and freeing a nullable pointer whose non-null case carries allocation ownership.

## Example 1: `free(NULL)`

```c
#include "pal.h"
#include

int free_null_literal(void) _ensures(return == 7)
{
free(NULL);
return 7;
}
```

### Expected behavior

The C standard specifies that `free(NULL)` performs no action. This function should verify and return `7`.

### Actual behavior

PAL emits:

```fstar
Pulse.Lib.C.Ref.free_ref Pulse.Lib.C.CoreRef.core_null
```

F* reports Error 189: `free_ref` expects a typed `ref`, but `core_null` has type `core_ref`.

## Example 2: Freeing a nullable, owned pointer

```c
#include "pal.h"
#include

_allocated typedef int *owned_int_ptr;

void free_nullable(_consumes _nullable owned_int_ptr p)
{
free(p);
}
```

### Expected behavior

- If `p` is null, no action or allocation ownership is required.
- Otherwise, `p` owns an initialized heap allocation, which is deallocated.
- No ownership is returned to the caller.

### Actual behavior

The generated precondition correctly makes ownership conditional on non-nullness, effectively:

```fstar
unless_null p (pts_to p value ** freeable p)
```

However, the body calls `free_ref p` unconditionally. F* reports Error 228 because it cannot obtain the unconditional `freeable p` and `pts_to_uninit p` resources required by that call.

## Acceptance criteria

- Both examples verify without adding a manual null check to the C source.
- Non-null deallocation continues to require allocation ownership.
- The argument to `free` is evaluated exactly once.
- Existing non-null deallocation behavior remains supported.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start at the PAL lowering for the C `free` entry point, where calls become `Pulse.Lib.C.Ref.free_ref`; inspect how `core_null` and `unless_null` ownership are represented. Verify both examples from `pal.h` without a manual null check, preserving single evaluation and ownership requirements for non-null deallocation.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.