.Heindl Solutions - Common problems with HALCON's HTuple and HString (C++)

Common problems with HALCON's HTuple and HString (C++)

2016-02-19 by Andreas Heindl



Suppose you have the following HalconCpp code to output a string saved in an HTuple:

#include <iostream>
#include <halconcpp/HalconCpp.h>
 
int main() {
  HalconCpp::HTuple text("Hello World");
  const char* s = text.S().Text();
  std::cout << s << '\n';
  return 0;
}

The program contains a sever bug in line 5-7 that I have seen pretty often. Do you catch it immediately?

Follow along to discover the bug for yourself:

  • Launch Developer Command Prompt for VS 2015 (this is x86 build environment)
set PATH=%HALCONROOT%\bin\x86sse2-win32;%PATH%
cl main.cpp /Zi /EHsc /I%HALCONROOT%/include /link halconcpp.lib /LIBPATH:"%HALCONROOT%/lib/x86sse2-win32
main.exe

The output will be something cryptic like ð☼▲x└ or even a crash.

What happened?

Investigation
  • VS2015 debugger to the rescue! Launch it from your Developer Command Prompt with devenv main.cpp /debugexe main.exe
  • set a breakpoint at the code line const char* s = text.S().Text();
  • Debug (F5)

To understand what happens, it is often helpful to see what your CPU really executes for a single C++ statement:

  • Press ALT+8 in VS2015 to see the assembler output
const char* s = text.S().Text();
 
0131C38A  lea         eax,[ebp-24h]  
0131C38D  push        eax  
0131C38E  lea         ecx,[text]  
0131C391  call        dword ptr [__imp_HalconCpp::HTuple::S (013BD218h)]  
0131C397  mov         dword ptr [ebp-10h],eax  
0131C39A  mov         ecx,dword ptr [ebp-10h]  
0131C39D  mov         dword ptr [ebp-14h],ecx  
0131C3A0  mov         byte ptr [ebp-4],1  
0131C3A4  mov         ecx,dword ptr [ebp-14h]  
0131C3A7  call        dword ptr [__imp_HalconCpp::HString::Text (013BD224h)]  
0131C3AD  mov         dword ptr [s],eax  
0131C3B0  mov         byte ptr [ebp-4],0  
0131C3B4  lea         ecx,[ebp-24h]  
0131C3B7  call        dword ptr [__imp_HalconCpp::HString::~HString (013BD228h)]  
 
  std::cout << s << '\n';
 
0131C3BD  push        0Ah  
0131C3BF  mov         edx,dword ptr [s]  
0131C3C2  push        edx

Probably you are not that firm in x86 assembly, but what should be easy to see is the call to HTuple::S, the call to HString::Text on the HString returned by HTuple::S and then the call to the destructor of the temporary HString::~HString. From now on every access to the internal data of HString returned by HString::Text is an access to undefined memory! So the output of s is an output of undefined memory, not of the expected 'Hello World'.

How to fix

Always assign output from myTuple.S().Text() immediatelly to a memory-managing class like std::string like so:

#include <iostream>
#include <string>
#include <halconcpp/HalconCpp.h>
 
int main() {
  HalconCpp::HTuple text("Hello World");
  //const char* s = text.S().Text(); //DO NOT USE
  std::string s = text.S().Text();
  std::cout << s << '\n';
  return 0;
}

btw: Similar to the problem above, one should never assign std::string's c_str() to a const char*.