Skip to content

Unsoundness bug: ref.func of imported function #57

@tlively

Description

@tlively

Problem

Consider this module:

(module $A
  (type $super (sub (func)))
  (type $sub (sub $super (func)))

  (import "B" "f" (func $f (type $super)))

  (global (export "f") (ref (exact $super)) (ref.func $f))
)

This module imports a function $f of type $super, then exports a reference to it with type (ref (exact $super)). According to the rules currently described in this proposal, this is fine because ref.func returns exact references. But this is unsound! The function B.f supplied at instantiation time might actually have been of type $sub. In that case it would be incorrect to type a reference to the function as (exact $super), because in fact the reference would be to a $sub.

Solution

A simple solution to this problem would be to type references to imported functions as inexact. This would be sound, but it would not be modular enough because it would create a difference in expressivity between imported and defined functions. The latter would be able to be referenced exactly and the former would not. This would inhibit e.g. module splitting where the secondary module contains a function that takes an exact reference to a function imported from the primary module. This would work before splitting the function definitions into separate modules, but not afterward.

To support this use case, we must make it possible to take exact references to imported functions. But for that to be sound, we must ensure that such imported functions have exactly the referenced type. Function imports already give a type for the imported function; we must now make it possible for that type to be exact.

There are a couple ways we could go about letting function imports be exact (e.g. allowing exactness in typeuse), but the least intrusive way is probably to make the externtype for functions be a heaptype rather than a typeuse. This is backward compatible because the binary representation of heaptype (an s33) includes all possible values of typeuse (a u32). The text format would have to be updated to allow typeuse or heaptype, though (and for best ergonomics, we would want to allow some combination of the two, so the params and results could still be given for exact imports).

The typing rule for ref.func would have to produce an exact reference for exactly imported functions and defined functions and an inexact reference for inexactly imported functions. This is probably best achieved by making funcs in the typing context be a list of possibly-exact heaptype rather than a list of deftype.

Credit

Credit for finding this bug goes to Seunghyun Lee (@0x10n) of CMU CSD / CyLab.

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