Null pointer in optimized code

When your C/C++ code is built with optimization, the null pointer detection log entry does not have the source line number.

To determine where the detection event occurs, complete the following steps:
  1. Rebuild the program with debug information and with no optimization. In this way, you can get the source line number in the log when a detection event occurs.
  2. Restart the debug session.
  3. Set the Stop at null pointers and addresses breakpoint.

If you cannot rebuild the program with no optimization, you can use the offset in the log to determine the cause of the detection event.

Example 1

The following log entry reports a null pointer in a C/C++ program that is built with optimization. In the log, the debugger source line number is unavailable, and the offset is 0x828.
A null pointer or null address was detected.
Module: QDBW
Object: qdbw
Function: customerInformationStructPointer()
Debugger source line: Unavailable
Offset: 0x828
ECB address: 0x1228D000
Instruction address: 0x9EC44890 
ECB TOD: DBF235E8091AAC04
ECB creation time: 12 Aug 2022, 18:49:23
At offset 0x828, there is a line CLC 0(4,8),0(3). In the preceding lines, there is an inline memcmp from the string.h file. At line 2579, the memcmp function is called from the program that is being debugged. You can determine the source line number from the listing. Because the program was built with debug information, the line number information is available in the listing. At line 2576, loc 1 291 means file number 1 at line 291. Search for file 1 in the listing, and you get this result: .file 1 /home/qdbw.c, which is at line 291 in the qdbw.c source file in the /home directory.
2576                            .loc  1 291
2577                            .align 2
2578                   .LM224:
2579                    # ***       compareResult =  memcmp(customerName,customerLastName,4);
2580                    # <<< begin inline copy of memcmp
2581                            .align 2
2582                   .LBB_232_26:
2583                    # *** line 509 ***
2584                            .loc  36 509
2585                            .align 2
2586                   .LM225:
2587                    # ***   inline int    memcmp (const void *__x, const void *__y, size_t\
2588                    #  __z)             //PJ46531
2589                    # ***          { return __memcmp(__x, __y, __z); }                    \
2590                    #                   //PJ46531
2591                    # *** line 510 ***
2592                            .loc  36 510
2593                            .align 2
2594                   .LM226:
2595 0824 A7390000              LGHI  3,0         # 0
2596 0828 D5038000              CLC   0(4,8),0(3)
To determine whether the customerName and customerLastName fields are null at that instruction, you can complete the following steps:
  1. Rebuild the program with debug information and with no optimization.
  2. Restart the debug session.
  3. Set the Stop at null pointers and addresses breakpoint.
  4. Open the Variables view to check the customerName and customerLastName fields.

Example 2

The following example is generated assembly code that was built from a C++ program with GCC 7, optimization level 2, and debug information. The first column shows the line numbers, and the third column has the offsets.
Note: This example applies to only this compiler. If you build the same program with a different compiler or optimization level, the generated assembly code might look different.
2420  423:/home/qdbw.cpp ****   memcpy(customerName,"JOHN",4);
2421  1227                           .loc 1 423 0
2422  1228 06fe A7290000             lghi    %r2,0   #,
2423  1229                   .LVL100:
2424  1230 0702 C0E50000             brasl   %r14,ctest@PLT  #,
2425  1230      0000
2426  1231                   .LVL101:
2427  1232                   # /home/qdbw.cpp:424:   memcpy(customerName,"JOHN",4);
2428  424:/home/qdbw.cpp ****   customerInformationStruct * customerDataPtr = getCustomerInformation(customerName);
2429  1233                           .loc 1 424 0
2430  1234 0708 C019D1D6             iilf    %r1,3520514261  # tmp69,
2431  1234      C8D5
2432  1235                   # /home/qdbw.cpp:425:   customerInformationStruct * customerDataPtr = getCustom
2433  425:/home/qdbw.cpp ****   int balance = customerDataPtr->balance;
2434  1236                           .loc 1 425 0
2435  1237 070e B904002B             lgr     %r2,%r11        #, customerName
2436  1238                   # /home/qdbw.cpp:424:   memcpy(customerName,"JOHN",4);
2437  424:/home/qdbw.cpp ****   customerInformationStruct * customerDataPtr = getCustomerInformation(customerName);
2438  1239                           .loc 1 424 0
2439  1240 0712 5010B000             st      %r1,0(%r11)     # tmp69, MEM[(void *)customerName_5]
2440  1241                   # /home/qdbw.cpp:425:   customerInformationStruct * customerDataPtr = getCustom
2441  425:/home/qdbw.cpp ****   int balance = customerDataPtr->balance;
2442  1242                           .loc 1 425 0
2443  1243 0716 C0E50000             brasl   %r14,_Z22getCustomerInformationPc@PLT   #,
2444  1243      0000
2445  1244                   .LVL102:
2446  1245                   # /home/qdbw.cpp:427:   if (balance != 0) {
2447  427:/home/qdbw.cpp ****     strcpy(customerName,"NA");
2448  1246                           .loc 1 427 0
2449  1247 071c BF132004             icm     %r1,3,4(%r2)    # tmp67, _9->balance
2450  1248 0720 A7840008             je      .L84    #,
A null pointer detection event occurs in the code, as shown in the following log entry:
 1 ======================================================
 2 Null address reference DETAILS:
 3 ======================================================
 4 A null pointer or null address was detected.
 5 Module: QDBW
 6 Object: qdbw
 7 Function: userDefinedTest()
 8 Debugger source line: Unavailable
 9 Offset: 0x71C
10 ECB address: 0x122EA000
11 Instruction address: 0x9E682A34
12 ECB TOD: DC3356327BF55845
13 ECB creation time: 03 Oct 2022, 13:59:31

In the log, the debugger source line number is unavailable, but you can look up offset 0x71C in the generated assembly code for more information about the detection event.

At line 2449, you can see the offset 0x71C in the third column. The commentaries indicate the variables that correspond to the assembly instruction operands. The commentary for this line shows a variable named balance.

Read the lines that precede line 2449 to see how the balance variable was set up.

Line 2446 checks whether the balance variable is zero.

At line 2441, the balance variable gets a value from the code customerDataPtr->balance.

At line 2437, the customerDataPtr field is set from a call to the getCustomerInformation function.

Therefore, the problem might be that the getCustomerInformation function returned zero. The detection event occurred because processing tries to access the balance member of the customerDataPtr field.