I have identified a very subtle memory management error that took me weeks to characterize.
I'm directly translating a working C++ program to Nim. The problem seems to be that the Nim code erroneously addresses the **seg** array beyonds its bounds, because the **k** values used to update the **nextp** array are thrown off, which causes incorrect values in **seg** to accumulate as the segment iterations increase. In **Listing 1** I show the corresponding code where the problem occurs. In it I output the values shown to see the difference in values that start to occur between the C++ and Nim code. Here I output the values for **k** and **seg[ki]** before they are updated in the loop. Both versions output the same values for the first complete segment iteration process. Starting within the second iteration those values start to become different, as **nextp** is not getting the correct values in the Nim version. Listing 1. C++ for (uint j=0; j < pcnt; ++j){ // for each prime r1..sqrt(N) if (nextp[row+j] < Kn) { // if 1st mult resgroup is within 'seg' uint k = nextp[row+j]; // starting from this resgroup in 'seg' uint ki = k*bprg + byti; // convert it to a byte address in seg[] uint prime = primes[j]; // get prime, convert it to number of uint prmstep = prime * bprg; // bytes to nextp primenth resgroup byte for (; k < Kn; k += prime){ // for each primenth byte to end of 'seg' cout << "(" << r << "," << prime << "," << k << "," << (seg[ki] & 255) << "," << biti << ") "; seg[ki] |= biti; // mark restrack bit in byte as nonprime ki += prmstep; // byte in next prime multiple resgroup } nextp[row+j] = k - Kn; // save 1st resgroup in next eligible seg } else nextp[row+j] -= Kn; // when 1st mult resgroup > seg resgroup range } ------------------------------------------------------------------------------- Nim for j, prime in primes: # for each prime r1..sqrt(N) if nextp[row + j] < uint(Kn): # if 1st mult resgroup is within 'seg' var k = int(nextp[row + j]) # starting from this resgroup in 'seg' var ki = k*bprg + byti # convert it to a byte addres in 'seg' let prmstep = prime * bprg # set number of bytes to next prime mult while k < Kn: # for each primenth byte to end of 'seg' write(stdout, "(",r, ",", prime, ",", k,",",seg[ki], ",", biti,") ") seg[ki] = seg[ki] or biti # mark restrack bit in byte as nonprime ki += prmstep # byte in next prime multiple resgroup k += prime # set resgroup of next prime multiple nextp[row + j] = uint(k-Kn) # save 1st resgroup in next eligible seg else: nextp[row+j] -= uint(Kn) # when 1st mult resgroup > seg resgroup range In **Listing 2** below, instead of outputting the values before they are updated I do it afterwards. This should throw a **Segfault** error, and did in the C++ code when it tried to output **seg[ki]** at an out-of-bound address. However, the Nim code keeps outputting out-of-bounds values for **seg[ki]** until the loop finished. After hitting the docs I saw that compiling using **\--d:release** turns off array bounds checking. So I compiled the **Listing 2** code as: **$ nim c -r file.nim** and now the Nim output also gave a segfault error, but it didn't occur at the same spot (**r** and **prime** values) as the C++ compiled code. So then I compiled the **Listing 1** Nim code similarly, and it gave better results, but it still produced errors. I'm convinced now that I can't rewrite the Nim code to produce the correct results because something is happening at the compile(r) level that I don't understand and can't control. Is there some compile flag to be set, or something that can be done, to make the Nim code work correctly, and/or is this a bug in the compile process? This was run with Nim 0.17.0, but I also got it to run under 0.12.0 (with a VB VM Linux distros) with same results. Listing 2 C++ for (uint j=0; j < pcnt; ++j){ // for each prime r1..sqrt(N) if (nextp[row+j] < Kn) { // if 1st mult resgroup is within 'seg' uint k = nextp[row+j]; // starting from this resgroup in 'seg' uint ki = k*bprg + byti; // convert it to a byte address in seg[] uint prime = primes[j]; // get prime, convert it to number of uint prmstep = prime * bprg; // bytes to nextp primenth resgroup byte for (; k < Kn; k += prime){ // for each primenth byte to end of 'seg seg[ki] |= biti; // mark restrack bit in byte as nonprime ki += prmstep; // byte in next prime multiple resgroup cout << "(" << r << "," << prime << "," << k << "," << (seg[ki] & 255) << "," << biti << ") "; } nextp[row+j] = k - Kn; // save 1st resgroup in next eligible seg } else nextp[row+j] -= Kn; // when 1st mult resgroup > seg resgroup range } ------------------------------------------------------------------------------- Nim for j, prime in primes: # for each prime r1..sqrt(N) if nextp[row + j] < uint(Kn): # if 1st mult resgroup is within 'seg' var k = int(nextp[row + j]) # starting from this resgroup in 'seg' var ki = k*bprg + byti # convert it to a byte addres in 'seg' let prmstep = prime * bprg # set number of bytes to next prime mult while k < Kn: # for each primenth byte to end of 'seg' seg[ki] = seg[ki] or biti # mark restrack bit in byte as nonprime ki += prmstep # byte in next prime multiple resgroup k += prime # set resgroup of next prime multiple write(stdout, "(",r, ",", prime, ",", k,",",seg[ki], ",", biti,") ") nextp[row + j] = uint(k-Kn) # save 1st resgroup in next eligible seg else: nextp[row+j] -= uint(Kn) # when 1st mult resgroup > seg resgroup range