ponyc: FFI call LLVM type signatures are not checked for conflicts

The Pony compiler doesn’t handle multiple calls to undeclared FFI calls for the same function with different signatures (which is a bug but typos happen) the same way as declared FFI calls. With a debug build of the compiler, it results in an assertion failure. With a release build, the behavior is undefined where ponyc seems to pick one at random.

The following code causes an assertion failure when compiled with a debug build of the compiler:

actor Main
  new create(env: Env) =>
    let x: ILong = -50
    let abs_x = @labs[I64](x)
    @printf[I32]("Abs of: %ld is: %lu\n".cstring(), x, abs_x)
    let y = @labs[I32](x)
    @printf[I32]("Abs of: %ld is: %lu\n".cstring(), x, y)

Results in:

$ ./build/debug/ponyc t
Building builtin -> /home/vagrant/up-ponyc/packages/builtin
Building t -> /home/vagrant/up-ponyc/t
Generating
 Reachability
 Selector painting
 Data prototypes
 Data types
 Function prototypes
 Functions
ponyc: src/libponyc/codegen/genexpr.c:268: gen_assign_cast: Assertion `LLVMGetTypeKind(r_type) == LLVMPointerTypeKind' failed.
Aborted (core dumped)

Ideally, undeclared FFI calls would be treated the same as declared FFI calls where there is a single signature for a specific function and any other calls to that function that don’t match that signature would throw an error that the signature doesn’t match the original declaration (from the first undeclared FFI call where it was encountered).

Also, it seems that FFI declarations are only package wide (https://github.com/ponylang/ponyc/blob/master/src/libponyc/pkg/ifdef.c#L217):

// FFI declarations are package wide, so check all modules in package.

However, in the case of FFIs, does it make sense to allow one package to define the call to labs as:

use @labs[I64](x: ILong)

while another package defines it as:

use @labs[I32](x: ILong)

I would expect that in a single Pony application, all FFI calls to the same function would be required to have the same signature. Maybe I’m missing a scenario where this makes sense?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 22 (21 by maintainers)

Commits related to this issue

Most upvoted comments

I second @dipinhora on thinking that multiple declarations of FFI functions should be identical. While it is true that using the same function with different signatures can be ABI-compatible, this is mostly possible by accident and isn’t portable in the general case. Also, since the function has a unique definition (and therefore a unique correct signature) on the C side, I think it should also have a unique declaration on the Pony side. That said, maybe we could have a special FFI-only type representing void* in a “less” type-safe way than Pointer[None]. That type would be convertible to and from any Pony type implemented as a pointer, which I think would solve the concerns expressed by @jemc.

Also, I agree with @agarman on pulling declarations from C headers. Maybe this RFC request could be extended to also cover function declarations.