3

Say my size_type is uint64_t, and I have the following loop (where sz is of size_type too)

for ( size_type i= 0; i < sz; ++i ) {
     //something
     if ( i+1 == sz ) { //<-- here
         ///
     }
}

Now when compiling this with flags -fno-omit-frame-pointer -fsanitize=undefined -O2 -fsanitize=address, I get a runtime error which says that in the place I marked here in the code snippet above, 2147483647 + 1 cannot fit into integer, and it is true that sz is something tad larger than 2^31-1. However, everything should be OK, beause uint64_t can hold the value, and by conversion rules i+1 should be promoted to uint64_t. What am I missing? EDIT: Isn't it so that uint64_t always has 64 bits? Then, 2147...-value is just 32 bits, and we should still be OK. I'm now running my thing without sanitizers, and no crash has occurred so far. EDIT:

clang version 8.0.0-3~ubuntu18.04.1 (tags/RELEASE_800/final) Target: x86_64-pc-linux-gnu Thread model: posix

and also I have linker flags as follows

set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer -fsanitize=undefined -fsanitize=address")

maybe that is interfering as well? I know the compiler explorer cannot reproduce the error, which is strange and calls for further investigation on my part.

Ilonpilaaja
  • 1,169
  • 2
  • 15
  • 26
  • 2
    I can't reproduce it. – Evg Jan 16 '20 at 10:39
  • which version of clang are you using? – Michael Kenzel Jan 16 '20 at 10:39
  • 3
    I'm assuming that you get the same ssue without `-fsanitize=address`, in which case I can't repro: https://godbolt.org/z/4hygZE (Also note that two or more people have just had to turn your code snippet into something that can actually compile and run. It would save everyone a lot of time if you provided that yourself - even more so because we wouldn't be stuck looking at code that doesn't actually reproduce the issue.) – Max Langhof Jan 16 '20 at 10:40
  • 1
    What abut checking this `if ( i == sz - 1 )`? As long as `sz > 0` this should be fine and no overflow of `i` should occur – Taron Jan 16 '20 at 10:57

1 Answers1

0

During the last iteration i = UINT64_MAX - 1, so i+1 = UINT64_MAX, so i <= UINT64_MAX in all cases.

for ( size_type i= 0; i < sz; ++i ) {
     //something
     if ( i+1 == sz ) { //<-- here
         ///
     }
}

There's no overflow. There's a possibility of bug in clang where it is trying to do incorrect induction variable optimization.

clang-8, rcx is incremented until it reaches 0. This may have introduced off by 1 error.

.LBB1_4:
        neg     rcx 
.LBB1_5:                                # =>This Inner Loop Header: Depth=1
        cmp     rax, rdi 
        jne     .LBB1_7
        mov     qword ptr [rsp - 8], rdi 
.LBB1_7:                                #   in Loop: Header=BB1_5 Depth=1
        add     rdi, 1
        inc     rcx 
        jne     .LBB1_5
.LBB1_8:

while clang-9. The rcx is decremented until it reaches 0.

.LBB1_7:
        ret 
.LBB1_6:                                #   in Loop: Header=BB1_4 Depth=1
        add     rdi, 1
        add     rcx, -1
        je      .LBB1_7
.LBB1_4:                                # =>This Inner Loop Header: Depth=1
        cmp     rax, rdi 
        jne     .LBB1_6
        mov     qword ptr [rsp - 8], rdi 
        jmp     .LBB1_6
A. K.
  • 34,395
  • 15
  • 52
  • 89