Sunday, June 15, 2025

C++ pointer bug

This C++ code has a significant bug that will cause undefined behavior:
#include <iostream>
class A {
  public:
    int val;
};
void reset(A *p_a) {
  if (p_a != NULL) {
      delete p_a;
  }
  p_a = new A();
}
int main() {
  A *p_a = new A();
  p_a->val = 5;
  std::cout << "Before reset, p_a->val:" << p_a->val << "\n";
  reset(p_a);
  std::cout << "After reset, p_a->val:" << p_a->val << "\n";
  return 0;
}

The reset function receives a copy of the pointer p_a, not a reference to it. When you modify p_a inside the function (with p_a = new A()), you're only changing the local copy - the original pointer in main() remains unchanged. What actually happens:

  1. p_a in main() points to an A object with val = 5 
  2. reset() receives a copy of this pointer 
  3. reset() deletes the original object (memory is freed) 
  4. reset() creates a new object, but assigns it only to the local copy 
  5. The original p_a in main() still points to the deleted memory 
  6. Accessing p_a->val after reset() is undefined behavior (accessing freed memory) 
The Fix: Pass the pointer by reference using a pointer-to-pointer or reference-to-pointer:
//Reference to pointer
void reset(A *&p_a) {
  if (p_a != nullptr) {
    delete p_a;
  }
  p_a = new A();
  // Call with: reset(p_a);

An even better fix is to use smart pointers, which removes the necessity for the reset function:

auto p_a = std::make_unique<A>();

You can detect such problems by enabling AddressSanitizer (ASAN) in Visual Studio:

  1. Right-click your project → Properties
  2. Go to Configuration Properties → C/C++ → General
  3. Set Enable Address Sanitizer to Yes (/fsanitize=address)
  4. Go to Configuration Properties → C/C++ → Optimization
  5. Set Optimization to Disabled (/Od) for better debugging
  6. Set Whole Program Optimization to No
  7. Go to Configuration Properties → C/C++ → Debug Information Format
  8. Set to Program Database (/Zi) or Program Database for Edit & Continue (/ZI)
In Eclipse CDT:

  1. Open your C/C++ project in Eclipse CDT
  2. Right-click project → Properties
  3. Navigate to C/C++ Build → Settings
  4. Under Tool Settings:
    1. GCC C++ Compiler → Miscellaneous
    2. GCC C Compiler → Miscellaneous
    3. Add to "Other flags": -fsanitize=address -g -O1
  5. Project Properties → C/C++ Build → Settings
  6. GCC C++ Linker → Miscellaneous
  7. Add to "Other objects": -fsanitize=address

No comments:

Post a Comment