A function named work__fp collides with PAL's generated wrapper for work
- 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