The program
This program keeps three ints in an array called a, then adds them up. An array's elements sit side by side in memory, one after another: a[0] holds 10, a[1] holds 20, a[2] holds 30.
a[i] means the element i places after the start, so a[0] is the first. With three elements the valid indexes are 0, 1 and 2. a[3] would be the spot just past the end: memory that is not part of a.
Line 5 counts i up from 0. Each round, line 6 reads a[i] and adds it to sum. After the rounds for i = 0, 1 and 2, sum is 60: the right answer so far.
Past the end
But line 5 tests i <= 3, so the loop runs a fourth time, with i = 3. Line 6 then reads a[3], past the end of the array. That read is undefined behaviour, UB for short.
Undefined behaviour means the C++ standard puts no requirements at all on what the program does. There is no promised error and no promised crash. Whatever happens next, the compiler has not broken any rule.
Built-in arrays have no bounds check: C++ trusts you to stay inside. This program compiles with -Wall -Wextra (flags that ask for extra warnings) and not one warning, and at run time nothing stops line 6 from reading a[3].
Run it and you might get a wrong total, a crash, or even 60 by luck. The result can change with the compiler, the flags or the machine. A program that seems to work can still have UB.
Compilers optimise on the promise that UB never happens. Since reading a[3] would be UB, an optimiser may reason that i never reaches 3 and drop the loop's end test. Turning on -O2 (optimisation) can change what a buggy program does.
Find it, fix it
Build with -fsanitize=address (AddressSanitizer, in GCC and Clang). It fences off the memory around a and checks every access. The bad read stops the program with a report that names the line: sum.cpp:6.
Change the test to i < 3, or let C++ do the counting with for (int x : a). Now the loop reads only a[0] to a[2], prints 60 every time, and the sanitizer stays quiet.
What happens
;; step 1/10 · program
sum.cpp
1 #include <iostream>
2 int main() {
3 int a[3] = {10, 20, 30};
4 int sum = 0;
5 for (int i = 0; i <= 3; ++i)
6 sum += a[i];
7 std::cout << sum << '\n';
8 }
line 3: int a[3] an array of 3 ints, stored next to each other
The C++ standard calls these cases undefined behaviour and places no requirements on them. cppreference's examples include memory access outside an array's bounds, signed integer overflow, dereferencing a null pointer and reading an uninitialised variable; using an object after its lifetime has ended (for example after delete) is undefined too. The figure does not show a value for a[3], because there is none to show: what a plain build prints is not defined and differs between compilers, settings and runs.