Skip to content

let a = someConst.unsafeAddr is very buggy and should be replaced #16794

@timotheecour

Description

@timotheecour

this recent PR #15466 enabled one to write let a = someConst.unsafeAddr; however this feature is very buggy, not documented, had 0 tests in the PR that introduced it and should be reverted; see upcoming proposal for a better and simpler way to solve nim-lang/RFCs#257 that has none of its drawbacks

Example 1

unsafeAddr doesn't work with most types

when true:
  template fn(a) =
    const b = a
    let c = b.unsafeAddr
  type A = object
    a0: int
  type B = ref A
  fn [1,2]
  fn @[1,2]
  fn A(a0:1)
  # these don't work: Error: expression has no address
  # fn "ab"
  # fn (1, 2)
  # fn 1
  # fn B(a0:1) # this one would work with const ref PR https://github.com/nim-lang/Nim/pull/15528

note that these would work with let c = b instead of let c = b.unsafeAddr

Example 2

when true:
  const a = [1,2]
  proc fn =
    let a1 = a.unsafeAddr
    a1[][0] = 7
    echo a1[]
    echo a
  static: fn()
  fn()

vm:
[7, 2] # modified from [1,2]
[1, 2] # unmodified from [1,2]: inconsistent
rt:
SIGBUS

Example 3

# sub.nim
when true:
  const a* = [1,2]
  proc fn1* =
    let a1 = a.unsafeAddr
    let a2 = a.unsafeAddr
    echo cast[int](a1)
    echo cast[int](a2)

# main.nim
when true:
  import sub
  proc fn2* =
    let a1 = a.unsafeAddr
    let a2 = a.unsafeAddr
    echo cast[int](a1)
    echo cast[int](a2)
  fn1()
  fn2()

prints:
4416151424
4416151424
4416151440 # address of a returned is different depending on which module it was called from
4416151440

and this is generated in each module:

static NIM_CONST tyArray__HU7qaqKu9czJLT84iCBJnsA TM__CLoBuXEHTlg1in6VU6Aqdg_2 = {((NI) 1),
((NI) 2)}

unlike what was required in nim-lang/RFCs#257

Example 4

unsafeAddr still doesn't help with types (including arrays) that (transitively) contain ref/ptr; it still needs #15528

Example 5

when defined case10:
  const a = @[1,2]
  proc fn* =
    let a1 = a.unsafeAddr
    let a2 = a.unsafeAddr
    echo cast[int](a1)
    echo cast[int](a2)
  static: fn()
  fn()

vm:
4378615304
4378615368 # different from previous line (inconsistent)
rt:
4382200032
4382200032 # same from previous line: inconsistent

Example 6

when true:
  const a1 = @[1,2]
  const a2 = [1,2]
  proc fn* =
    let b1 = a1.unsafeAddr
    echo cast[int](b1) # ok
    let b2 = a2.unsafeAddr
    echo cast[int](b2) # Error: unhandled exception: 'intVal' is not accessible using discriminant 
  static: fn()

Example 7

when true:
  const a = @[1,2]
  let b = a.unsafeAddr
  proc fn1 =
    b[][0] = 7
    echo b[]
  fn1()

nim r main: SIGBUS
nim r -b:cpp main: prints @[7, 2]

Example 8

when true:
  const a = [1,2]
  let b = a.unsafeAddr
  proc fn1 =
    b[][0] = 7
    echo b[]
  fn1()

nim r main: prints [1, 2] with -d:danger, or SIGBUG without
nim r -b:cpp main: prints [7, 2] with or without -d:danger

Additional Information

1.5.1 2b5841c

links

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions