Skip to content

I32.clz_unsafe is *really* unsafe #2895

Description

@fweimer

Consider this example program:

actor Main
  new create(env: Env) =>
    let array = Array[String]
    array.append(env.args)
    while array.size() < 32 do
      array.push("")
    end
    (let index, let used) = try
         env.args(1)?.read_int[U32]()?
       else
         env.err.print("error: invalid index")
         return
       end
    env.out.print("info: index: " + index.string())
    env.out.print("info: used: " + used.string())
    try
      if array.size() != 32 then
        env.err.print("error: array has wrong size")
        return
      end
      env.out.print(array(magic(index).usize())?)
      env.out.print("info: magic: " + magic(index).string())
      env.out.print("info: no error thrown")
    else
      env.out.print("info: error thrown")
    end      
  fun magic(x: U32): U32 =>
    let y = x.clz_unsafe()
    if y < 32 then
      y
    else
      0
    end

(This can undoubtedly be reduced further, but it will be really brittle.)

When I run it, I get this:

./unsafe 0
Segmentation fault

I believe the reason is this: LLVM treats undefined as really undefined. The bounds check y < 32 is optimized away, and on some CPUs (mine is a Core m7-6Y75), when compiling natively, clz_unsafe is implemented as lzcnt, which yields 32 for a zero input value. The subsequent code gets confused by this because according to LLVM semantics, the value 32 is impossible here. However, this is not an LLVM bug—it does what the Pony compiler instructs it to do.

My compiler:

0.24.4-fff531cf [release]
compiled with: llvm 3.9.1 -- cc (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Defaults: pic=true ssl=openssl_1.1.0

The reproducer is probably brittle, so unless you have the same environment, it will not work.

The same issue applies to all unsafe arithmetic operations, with different reproducers. (clz_unsafe was literally the first one I tried.) I think it would be reasonable to simply remove all the unsafe arithmetic methods because the performance benefits will be extremely narrow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions