Skip to content
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

seq pop malfunctions in array of seqs #24596

Open
bptato opened this issue Jan 1, 2025 · 2 comments
Open

seq pop malfunctions in array of seqs #24596

bptato opened this issue Jan 1, 2025 · 2 comments

Comments

@bptato
Copy link
Contributor

bptato commented Jan 1, 2025

Description

Following code

proc main() =
  var trimMap = [@[1], @[2]]
  var z = 0
  for j in 0 ..< 2:
    var i = trimMap.high
    while i >= 0:
      #let len {.volatile} = trimMap[i].len # this way it "works"
      let len = trimMap[i].len
      if len > 0:
        z = trimMap[i].pop()
        echo "set"
        break
      dec i
    echo "popped ", i
    doAssert z != 0
  echo "z", z

main()

prints:

set
popped 1
set
popped 1
fatal.nim(53)            sysFatal
Error: unhandled exception: z.nim(15, 5) `z != 0`  [AssertionDefect]

on both devel and 2.0.14, when compiled like:

nim c --mm:arc -d:danger -d:lto --cc:clang z.nim

with clang version 18.1.8. (-d:release instead of -d:danger has the same effect.)

The crash disappears if I do any of:

  • set len to volatile
  • --passc:-fno-strict-aliasing
  • disable LTO
  • --mm:refc

It also disappears if I switch to GCC, but this is probably by accident.
The original program that I reduced this from crashes under GCC as well.

len is supposed to be set in shrink:
/* z.nim.c */
struct tySequence__qwqHTkRvwhrRyENtudHQ7g {
	NI len;
	tySequence__qwqHTkRvwhrRyENtudHQ7g_Content* p;
};
struct tySequence__qwqHTkRvwhrRyENtudHQ7g_Content {
	NI cap;
	NI data[SEQ_DECL_SIZE];
};

static N_INLINE(NI, pop__z_u27)(tySequence__qwqHTkRvwhrRyENtudHQ7g* s_p0) {
	NI result;
NI L;
NI T1_;
T1_ = (*s_p0).len;
L = ((NI) (T1_ - ((NI) 1)));
result = ((*s_p0)).p->data[L];
((*s_p0)).p->data[L] = 0;
shrink__z_u42(s_p0, (L));
	return result;
}

/* system.nim.c */
typedef struct tyObject_NimSeqPayload__g7Ny9bTlNzn6dsxoJOHv6LQ tyObject_NimSeqPayload__g7Ny9bTlNzn6dsxoJOHv6LQ;
/* ^ incomplete struct; never gets defined anywhere */
struct tyObject_NimSeqV2__PEQQ33xihBDluJkSxo81LQ {
	NI len;
	tyObject_NimSeqPayload__g7Ny9bTlNzn6dsxoJOHv6LQ* p;
};

N_LIB_PRIVATE N_NIMCALL(void, shrink__z_u42)(tySequence__qwqHTkRvwhrRyENtudHQ7g* x_p0, NI newLen_p1) {
	(*((tyObject_NimSeqV2__PEQQ33xihBDluJkSxo81LQ*) (x_p0))).len = newLen_p1;
}

Perhaps the cast violates strict aliasing?

Nim Version

Nim Compiler Version 2.3.1 [Linux: amd64]
Compiled at 2025-01-01
Copyright (c) 2006-2025 by Andreas Rumpf

git hash: 3dda60a8ce32cb7d5e3e99111399a1550c145176
active boot switches: -d:release

Current Output

No response

Expected Output

set
popped 1
set
popped 0
z1

Known Workarounds

No response

Additional Information

ETA: this seems to fix it

diff --git a/lib/system/seqs_v2.nim b/lib/system/seqs_v2.nim
index 572e77408..3817b6bc5 100644
--- a/lib/system/seqs_v2.nim
+++ b/lib/system/seqs_v2.nim
@@ -133,7 +133,7 @@ proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [], raises: [].} =
         reset x[i]
     # XXX This is wrong for const seqs that were moved into 'x'!
     {.noSideEffect.}:
-      cast[ptr NimSeqV2[T]](addr x).len = newLen
+      cast[ptr int](addr x)[] = newLen
 
 proc grow*[T](x: var seq[T]; newLen: Natural; value: T) {.nodestroy.} =
   let oldLen = x.len

C allows aliasing with the first member, so it makes sense.
But if it's a strict aliasing problem, then it's not an adequate fix, because the cast is also performed in other functions.

@juancarlospaco
Copy link
Collaborator

!nim c --gc:arc -d:lto

proc main() =
  var trimMap = [@[1], @[2]]
  var z = 0
  for j in 0 ..< 2:
    var i = trimMap.high
    while i >= 0:
      #let len {.volatile} = trimMap[i].len # this way it "works"
      let len = trimMap[i].len
      if len > 0:
        z = trimMap[i].pop()
        echo "set"
        break
      dec i
    echo "popped ", i
    doAssert z != 0
  echo "z", z

main()

Copy link
Contributor

github-actions bot commented Jan 1, 2025

🐧 Linux bisect by @juancarlospaco (collaborator)
devel 👍 OK

Output


Filesize 91.98 Kb (94,192 bytes)
Duration

stable 👍 OK

Output


Filesize 91.75 Kb (93,952 bytes)
Duration

2.0.10 👍 OK

Output


Filesize 92.02 Kb (94,224 bytes)
Duration

2.0.0 👍 OK

Output


Filesize 88.00 Kb (90,112 bytes)
Duration

1.6.20 👍 OK

Output


Filesize 86.63 Kb (88,704 bytes)
Duration

1.4.8 👎 FAIL

Output


Filesize 86.63 Kb (88,704 bytes)
Duration

1.2.18 👍 OK

Output


Filesize 82.89 Kb (84,880 bytes)
Duration

1.0.10 👎 FAIL

Output


Filesize 82.89 Kb (84,880 bytes)
Duration

#a4f9bc55c ➡️ 🐛

Diagnostics

cooldome introduced a bug at 2020-10-28 13:00:49 +0000 on commit #a4f9bc55c with message:


The bug is in the files:


The bug can be in the commits:

(Diagnostics sometimes off-by-one).

Stats
  • GCC 11.4.0
  • Clang 14.0.0
  • NodeJS 20.5
  • Created 2025-01-01T17:11:03Z
  • Comments 1
  • Commands nim c --gc:arc -d:lto -d:nimArcDebug -d:nimArcIds --run -d:nimDebug -d:nimDebugDlOpen -d:ssl -d:nimDisableCertificateValidation --forceBuild:on --colors:off --verbosity:0 --hints:off --lineTrace:off --nimcache:/home/runner/work/Nim/Nim --out:/home/runner/work/Nim/Nim/temp /home/runner/work/Nim/Nim/temp.nim

🤖 Bug found in 3 mins bisecting 327 commits at 82 commits per second

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

2 participants