FStarLang / FStarLang/pal

A function named work__fp collides with PAL's generated wrapper for work

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

Description

## Summary

PAL uses `__fp` as the internal name of a generated function-pointer wrapper, but stores that name in the same namespace as ordinary C functions.

A valid user-defined function named `work__fp` therefore collides with the wrapper generated when taking the address of `work`. PAL emits invalid Pulse rather than keeping the two entities distinct.

Reproduced on `main` at `9ec4165`.

## Reproducer

```c
#include "pal.h"

int work__fp(void) _ensures(return == 2)
{
return 2;
}

int work(void) _ensures(return == 1)
{
return 1;
}

int call_helper(void) _ensures(return == 2)
{
return work__fp();
}

void store_pointer(void)
{
int (*fp)(void) = work;
}
```

## Expected behavior

`work__fp` is an ordinary C function, distinct from `work` and from any wrapper PAL generates internally.

PAL should preserve:

- Direct calls to `work__fp`, returning `2`.
- Direct calls to `work`, returning `1`.
- Function-pointer creation for `work`.

The generated wrapper must have an identity that cannot collide with the user-defined function.

## Actual behavior

For the declaration order above, PAL emits this definition inside `Func_work__fp.fst`:

```pulse
divergent fn Funcptr_work.func_work__fp ()
returns return_1 : Int32.t
ensures (with_pure ((id #int (Int32.v return_1)) = 2))
{
return 2l;
}
```

The ordinary function's definition is incorrectly qualified as belonging to the wrapper module.

F* fails during dependency generation with Error 168, a syntax error at the qualified function name.

Native C compilation succeeds, and direct calls return the expected values. Renaming only the ordinary function from `work__fp` to `helper` makes all generated modules, including the function-pointer wrapper, verify.

## Suspected cause

In `src/pass/emit.rs:153–176`, `build_fn_module_map` registers both ordinary functions and synthetic wrapper names in the same map.

The wrapper is inserted under the key:

```rust
format!("{}__fp", n)
```

`emit_fnptr_name` also represents the wrapper using `Name::Fn`, the same variant used for ordinary functions.

Consequently, the real function `work__fp` and the synthetic wrapper for `work` are treated as the same identifier. A later map insertion overwrites the earlier module association.

## Suggested direction

Give synthetic wrappers a separate internal identity, such as a dedicated `Name` variant, rather than representing them as ordinary C function names with a suffix.

Use that identity consistently for wrapper definitions, references, and module ownership.

## Regression coverage

- A real `work__fp` function alongside an address-taken `work`.
- Both declaration orders.
- Direct calls to the real `work__fp`.
- Function-pointer creation and calls through `work`.
- Generated declarations and references must resolve to the correct distinct modules.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in src/pass/emit.rs:153–176 and trace build_fn_module_map and emit_fnptr_name through wrapper definitions, references, and module ownership. Run the supplied C reproducer in both declaration orders, then add regression coverage for direct work__fp calls, work pointer creation and calls, and distinct generated declarations and references.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
compilers, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.