Skip to content

In a module that defines free, free(xs) of a slice calls the module's own free with the slice's pointer #3116

Closed

Description

@nicolas-maman

A module may define a function named free, and many do, since bignum.free, json.free and sm4.free are what their callers write. Inside such a module, every call free(x) is that function. The builtin free, the one release of a make([]T, n) buffer, is out of reach. A slice given to the module's free(n: ptr) decays to its pointer without a word:

// std/bignum/module.ae
free(n: ptr) {                  // bignum.free, a BN handle
    bn = n as *BN
    if bn.mag != null { free(bn.mag) }   // bn.mag is an int[]: calls bignum.free again
    libc_free(n)
}

That compiles and crashes: the inner call reads the limbs as a *BN (0xabab... in a debug build). Any module with a free API that holds a slice has the choice between a crash and freeing make's storage with libc behind the language's back.

Fix: a call free(x) whose argument is a slice frees the slice with the builtin, also in a module that defines free, unless that function's own parameter is a slice. The module's function can only read the slice's pointer as its own object, so it never means to release the slice. The merger marks the intra-module call it renames, and the checker decides once the argument's type is known. A free of a view is refused as it is everywhere else (#3072). Tests cover a module whose free(p: ptr) frees a slice field and a temporary slice, a module whose free(xs: int[]) takes the slice itself (its own function runs), and the view refusal inside such a module.

Found on #3101, moving std.bignum's limbs from std.intarr onto int[] (#3107).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions