Skip to content

A function declared inside a function body is dropped, leaving an unresolvable call #285

Description

@akashlal

Versions: PAL a9ebbed · F*/Pulse nightly 2026-08-27 · Clang 20.1.8

Summary

A function declared inside a function body — the K&R-era idiom of declaring a library function locally instead of including its header — is dropped, and the call then has no definition to resolve to.

PAL does report unsupported variable declaration Function, but translation continues and emits a module that cannot verify.

Minimal repro

#include "pal.h"

/* 1. FAILS -- callee declared inside the body. */
double local_decl(_array double *v, unsigned n)
  _preserves(v._length == n)
  _requires(n > 0)
{
    double floor();
    double d = floor(2.0);
    return v[0] + d;
}

/* 2. control -- identical, callee declared at FILE scope.  VERIFIES */
double floor_at_file_scope();

double control_file_scope(_array double *v, unsigned n)
  _preserves(v._length == n)
  _requires(n > 0)
{
    double d = floor_at_file_scope();
    return v[0] + d;
}

/* 3. control -- no call at all.                            VERIFIES */
double control_no_call(_array double *v, unsigned n)
  _preserves(v._length == n)
  _requires(n > 0)
{
    return v[0];
}
$ pal --outdir out repro.c
error: unsupported variable declaration Function
error: (internal, after merge) unknown function floor
error: (internal, after normalize_casts) unknown function floor
error: (internal, after elim_cis) unknown function floor
error: (internal, after elim_cis) cannot infer type of floor(N): floor is not a function

$ run-fstar.sh --include out out/Func_local_decl.fst
Error 72: Identifier not found: func_floor

$ run-fstar.sh --include out out/Func_control_file_scope.fst   # Verified
$ run-fstar.sh --include out out/Func_control_no_call.fst      # Verified

All three functions carry the same trivially provable array index (v[0]), so the only variable is where the callee is declared.

Impact

We are using PAL to prove spatial memory safety on the Olden and Ptrdist benchmark suites, holding the C source fixed and adding only annotations. Older C in these suites declares floor, sqrt, atoi and similar locally rather than including a header, so the construct shows up in real code.

The impact is modest on its own — in olden/bh it accounts for 2 of 73 obligations — but the diagnostic is misleading: the reported error is about a variable declaration, and the eventual failure is an unresolved identifier in generated code, so the connection back to the local declaration is not obvious.

Suggested behaviour

Either treat a function declared in block scope the same as one declared at file scope (C's scoping rules make this equivalent for the callee's type), or make the translation error fatal so it is not silently followed by an unverifiable module.

Related: #92 (Provide specifications for C library functions), #73 (Support separate function declarations, closed).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions