Skip to content

Unexpected behaviour when modifying/adding data to a table #13454

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
zevv opened this issue Feb 21, 2020 · 6 comments
Open

Unexpected behaviour when modifying/adding data to a table #13454

zevv opened this issue Feb 21, 2020 · 6 comments

Comments

@zevv
Copy link
Contributor

zevv commented Feb 21, 2020

Apologies for the bad subject, but this is hard to explain in one line.

Reported on #Nim by Stuffe with some modifications by me. The following snippet shows flakey behaviour when modifying a table in a specific way. My hunch is that this has to do with Nim messing up the internal Table bookkeeping when the internal data structures are resized.

The expected output of this program would be N 123 for every line, but for N==43 and N==86 the output is N 0

import tables

type my_object = object
  id: int

for l in 1..90:

  var table = newTable[int, my_object]()
 
  for id in 0..<l:
    table[id] = my_object(id: 0)
                              
  proc returns_123(): int =
    table[l] = my_object()
    return 123                
            
  table[0].id = returns_123()
                                                                                           
  echo l, " ", table[0].id   
@zevv zevv changed the title UB when modifying/adding data to a table Unexpected behaviour when modifying/adding data to a table Feb 21, 2020
@zevv
Copy link
Contributor Author

zevv commented Feb 21, 2020

#13430 ?

@andreaferretti
Copy link
Collaborator

This seems the same type of issue as #13430

@andreaferretti
Copy link
Collaborator

Basically, use a TableRef, or avoid modifiying tables while also assigning to them

@Araq
Copy link
Member

Araq commented Feb 21, 2020

It's much trickier to fix/report than #13430 though.

@Araq
Copy link
Member

Araq commented Feb 21, 2020

Workaround for now:

import tables

type my_object = object
  id: int

for l in 1..90:

  var table = newTable[int, my_object]()

  for id in 0..<l:
    table[id] = my_object(id: 0)

  proc returns_123(): int =
    table[l] = my_object()
    return 123

  let tmp = returns_123()
  table[0].id = tmp

  echo l, " ", table[0].id

@timotheecour
Copy link
Member

here's a reduced example without any import nor Table:

  type Foo = object
    id: int

  type Tab = ref object
    s: seq[Foo]

  proc `[]`(a: Tab, index: int): var Foo = a.s[index]

  for i in 1..<100:
    var t = Tab()
    proc bar(): int =
      t.s.add Foo(id: -2)
      10

    for id in 0..<i:
      t.s.add Foo(id: -1)

    t[0].id = bar()

    if t[0].id != 10:
      echo i, " ", t[0].id

prints:

1 -1
2 -1
4 -1
8 -1
16 -1
32 -1
64 -1

note

the closure bar() is equivalent to calling the following non closure proc:

  proc bar2(t: Tab): int =
    t.s.add Foo(id: -2)
    10

in the expression t[0].id = bar() (or equivalent t[0].id = bar2(t)), nothing violates https://nim-lang.org/docs/manual_experimental.html#aliasing-restrictions-in-parameter-passing

So https://nim-lang.org/docs/manual_experimental.html#aliasing-restrictions-in-parameter-passing should be amended ; maybe it should consider a full statement; but I'mnot sure that's possible without being overly restrictive

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants