最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - C++CLI Several Memory error on cpp header file wrapper - Stack Overflow

programmeradmin0浏览0评论

I'm trying to create a C++/CLI wrapper of a cpp header file. I have only access to the header files and to the .lib files.

This is the original IRCalibrationManager.h file that I'm trying to wrap:

#ifndef IRCALIBRATIONMANAGER_H
#define IRCALIBRATIONMANAGER_H

#include <fstream>
#include <string>
#include "unicode.h"
#include "IRArray.h"
#include "irdirectsdk_defs.h"

class ConfigCali;

namespace evo
{

struct IRTempRange
{
  int tMin;
  int tMax;
};

struct IROptics
{
  IROptics(std::size_t countTempRanges = 0) : 
    tempRanges(countTempRanges),
    text(1, GEN_L("\0"))
  {
  }

  int fov;
  IRArray<IRTempRange> tempRanges;
  IRArray<Tchar> text;
  double radialDistortion;
};

#if _WIN32 && !IRDIRECTSDK_STATIC
EXPIMP_TEMPLATE template class __IRDIRECTSDK_API__ IRArray<IROptics>;
#endif

/**
 * @class IRCalibrationManager
 * @brief Class for checking and downloading calibration files for IRImager devices
 */
class __IRDIRECTSDK_API__ IRCalibrationManager
{

public:

  /**
   * Constructor
   **/
  IRCalibrationManager(const Tchar* pathCali = nullptr, const Tchar* pathFormats = nullptr, const Tchar* dirDeadPixels = nullptr);

  /**
   * Destructor
   **/
  ~IRCalibrationManager();

  /**
   * Static singleton instance accessor
   * @return singleton instance of IRCalibrationManager class
   **/
  static IRCalibrationManager* getInstance();

   /**
   * Static release function, new with T#2251
   **/
  static void releaseInstance();

  //Disable copy, as no deep copy is implemented and destructor would delete the memory for all objects
  IRCalibrationManager& operator=(const IRCalibrationManager&) = delete;
  IRCalibrationManager(const IRCalibrationManager&) = delete;
  
  /**
   * Set calibration directory
   * @param[in] dir full directory path to folder containing calibration files
   **/
  void setCalibrationDir(const Tchar* dir);

  /**
   * Set formats directory
   * @param[in] dir full directory path to folder containing the Formats.def file
   **/
  void setFormatsDir(const Tchar* dir);


  /**
   * Set dead pixel directory
   * @param[in] dir full directory path to folder containing the deadpixels file
   **/
  void setDeadPixelDir(const Tchar* dir);
  

  /**
   * Get calibration directory
   * @return full directory path to folder containing calibration files
   **/
  const Tchar* getCalibrationDir();

  /**
   * Get formats directory
   * @return full directory path to folder containing the Formats.def file
   **/
  const Tchar* getFormatsDir();
  
  /**
   * Get dead pixel directory
   * @return full directory path to folder containing dead pixel files
   **/
  const Tchar* getDeadPixelDir();

  /**
  * Check existence of calibration file set.
  * @param[in] serial Serial number of device
  * @return Returns NULL-pointer if no file is missing, otherwise path of missing files as comma separated list. Free returned pointer with delete[].
  */
  Tchar* checkCalibration(unsigned long serial);

  /**
   * Check available optics for a specific device
   * @param[in] serial serial number of device
   * @return vector of available optics (fov)
   */
  const IRArray<IROptics>* getAvailableOptics(unsigned long serial);

  /**
  * Get (concat) path and name of configuration file
  * @param[out] Path of configuration file
  * @param[in] directory Directory of configuration file
  * @param[in] maxLen Maximum character length of path parameter
  * @param[in] fileName Name of configuration file
  * @param[in] extension Extension of configuration file
  */
  static bool createConfigFilepath(Tchar* path, const Tchar* directory, short maxLen, const Tchar* fileName, const Tchar* extension);

  /**
  * Generate XML configuration for a specific device
  * @param[in] serial Serial number of device
  * @return text content of standard configuration file
  */
  IRArray<Tchar> generateConfiguration(unsigned long serial);

  /**
   * Check for Internet access to calibration files
   * @return availability flag
   */
  static bool isOnlineCalibrationRepoAccessible();

  /**
   * Download calibration files for a specific serial number
   * @param serial Serial number of device
   */
  bool downloadCalibration(unsigned long serial);

  /**
   * ONLY LINUX: Copy calibration files from local device, e.g., USB stick
   * @param[in] serial serial number of device for which calibration files are to be found
   * @param[in] srcDir source directory to search for calibration files
   * @return success of search and copy operation
   */
  bool copyCalibrationFromLocalRepo(unsigned long serial, const char* srcDir);

  /**
  * Determine serial number of attached device(s)
  * @param[in] serial Serial number (pass 0 to search for serial of an attached device, pass serial to search for a specific device).
  * @param[in] skip Skips the first n results. Use this to detect multiple devices.
  * @return success flag
  */
  static bool findSerial(unsigned long &query, unsigned int skipNResults = 0);

private:


  void init(const Tchar* caliPathDefault, const Tchar* formatsPathDefault);

  static bool downloadTarget(Tchar* listOfMissingFiles, unsigned long serial, const Tchar* targetDir);

  bool checkCaliFiles(const Tchar* CaliDirectory, int SerialNumber, Tchar* ListOfMissingFiles, int* Maxlen, const Tchar* configPattern, const Tchar* caliPattern, const Tchar* kennliniePattern, const Tchar* separator);

  Tchar* _pathCali;

  Tchar* _pathFormats;

  Tchar* _pathDeadPixels;

  Tchar* _framerateText;
  
  IRArray<IROptics> _optics;

  static IRCalibrationManager* _this;
};

}

#endif // IRCALIBRATIONMANAGER_H

This is the IRArray.h file:

#include <cstddef>
#include <stdexcept>
#include <sstream>

namespace evo
{

/**
 * @class IRArray
 * @brief C-Array wrapper for handle size, copy and memory
 * @author Helmut Engelhardt (Evocortex GmbH)
 */
template <class T>
class IRArray
{
private:
    //Array pointer
    T* _data;

    //Size of array
    std::size_t _size;
public:


   /**
   * Initialize array with given size
   * @param[in] size Size of array
   */
    IRArray(std::size_t size);

    /**
     * Initialize array with given size and data.
     * @param[in] size Size of array
     * @param[in] data Pointer to array to copy from. Has to be at least the given size!
     */
    IRArray(std::size_t size, const T* const data);

    /**
     * Copy constructor to copy given IRArray
     * @param[in] obj IRArray to copy
     */
    IRArray(const IRArray<T> &obj);

    /**
     * Deconstructor. Handles deletion of array
    */
    ~IRArray();

    /**
     * Assignment operator for copy IRArray
     * @param[in] obj IRArray to copy
     */
    IRArray<T>& operator=(const IRArray<T>& obj);
    
    IRArray<T>& operator=(IRArray<T>&& obj);

    /**
     * Index operator. Throws std::out_of_range if index out of range.
     * @param[in] index Index of required data
     */
    T& operator[](const std::size_t index);

    /**
     * Const index operator. Throws std::out_of_range if index out of range.
     * @param[in] index Index of required data
     */
    const T& operator[](const std::size_t index) const;

    /**
     * Returns size of array
     * @return Size of array
     */
    std::size_t size() const;

    /**
     * Returns pointer to array
     * @return Array pointer
     */
    T* const data() const;
};

} //namespace evo

template <class T>
evo::IRArray<T>::IRArray(std::size_t size)
{
    _size = size;
    if(_size > 0)
    {
        _data = new T[_size];
    }
    else
    {
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>::IRArray(std::size_t size, const T* const data)
{
    _size = size;
    if(_size > 0)
    {
        _data = (T*)(new char[size * sizeof(T)]);
        std::copy(data, data + _size, _data);
    }
    else
    {
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>::IRArray(const evo::IRArray<T> &obj) : IRArray(obj._size, obj._data)
{
}

template <class T>
evo::IRArray<T>::~IRArray()
{
    if(_data != nullptr)
    {
        delete[] _data;
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>& evo::IRArray<T>::operator=(const evo::IRArray<T>& obj)
{
    IRArray<T> tmp(obj);
    _size = tmp._size;
    _data = tmp._data;

    tmp._size = 0;
    tmp._data = nullptr;
    return *this;
}

template <class T>
evo::IRArray<T>& evo::IRArray<T>::operator=(evo::IRArray<T>&& obj)
{
    _size = obj._size;
    _data = obj._data;

    obj._size = 0;
    obj._data = nullptr;
    return *this;
}

template <class T>
T& evo::IRArray<T>::operator[](const std::size_t index) 
{ 
    if (index < 0 || index >= _size) 
    { 
        std::stringstream ss;
        ss << "Index " << index << " out of range. [0.." << _size << "[";
        throw std::out_of_range(ss.str());
    }
    return _data[index]; 
}

template <class T>
const T& evo::IRArray<T>::operator[](const std::size_t index) const
{
    if (index < 0 || index >= _size) 
    {
        std::stringstream ss;
        ss << "Index " << index << " out of range. [0.." << _size << "[";
        throw std::out_of_range(ss.str());
    }
    return _data[index];
}

template <class T>
std::size_t evo::IRArray<T>::size() const
{
    return _size;
}

template <class T>
T* const evo::IRArray<T>::data() const
{
    return _data;
}

Initially I wrote this code:

String^ GenerateConfiguration(unsigned long serial)
{
    try
    {
        
        evo::IRArray<Tchar> result = _nativeManager->generateConfiguration(serial);
        Tchar* nativeData = result.data();

        return gcnew String(nativeData);
    }
    catch (const std::exception& ex)
    {
        throw gcnew Exception(gcnew String(ex.what()));
    }
    catch (...)
    {
        throw gcnew Exception("An unknown error occurred.");
    }
}

But I have always errors. So I reduce the code to this version but the problems persist.

String^ GenerateConfiguration(unsigned long serial)
{
    try
    {
        evo::IRArray<Tchar> result = _nativeManager->generateConfiguration(serial);
        return gcnew String("nativeData");
    }
    catch (const std::exception& ex)
    {
        throw gcnew Exception(gcnew String(ex.what()));
    }
    catch (...)
    {
        throw gcnew Exception("An unknown error occurred.");
    }
}

These are the errors:

_CrtlsValidHeapPointer(block)

is_block_type_valid(header->_block_use)

It's finish into a System.AccessViolationException in the IRArray<T>::~IRArray() at this line _data = nullptr;

I'm trying to create a C++/CLI wrapper of a cpp header file. I have only access to the header files and to the .lib files.

This is the original IRCalibrationManager.h file that I'm trying to wrap:

#ifndef IRCALIBRATIONMANAGER_H
#define IRCALIBRATIONMANAGER_H

#include <fstream>
#include <string>
#include "unicode.h"
#include "IRArray.h"
#include "irdirectsdk_defs.h"

class ConfigCali;

namespace evo
{

struct IRTempRange
{
  int tMin;
  int tMax;
};

struct IROptics
{
  IROptics(std::size_t countTempRanges = 0) : 
    tempRanges(countTempRanges),
    text(1, GEN_L("\0"))
  {
  }

  int fov;
  IRArray<IRTempRange> tempRanges;
  IRArray<Tchar> text;
  double radialDistortion;
};

#if _WIN32 && !IRDIRECTSDK_STATIC
EXPIMP_TEMPLATE template class __IRDIRECTSDK_API__ IRArray<IROptics>;
#endif

/**
 * @class IRCalibrationManager
 * @brief Class for checking and downloading calibration files for IRImager devices
 */
class __IRDIRECTSDK_API__ IRCalibrationManager
{

public:

  /**
   * Constructor
   **/
  IRCalibrationManager(const Tchar* pathCali = nullptr, const Tchar* pathFormats = nullptr, const Tchar* dirDeadPixels = nullptr);

  /**
   * Destructor
   **/
  ~IRCalibrationManager();

  /**
   * Static singleton instance accessor
   * @return singleton instance of IRCalibrationManager class
   **/
  static IRCalibrationManager* getInstance();

   /**
   * Static release function, new with T#2251
   **/
  static void releaseInstance();

  //Disable copy, as no deep copy is implemented and destructor would delete the memory for all objects
  IRCalibrationManager& operator=(const IRCalibrationManager&) = delete;
  IRCalibrationManager(const IRCalibrationManager&) = delete;
  
  /**
   * Set calibration directory
   * @param[in] dir full directory path to folder containing calibration files
   **/
  void setCalibrationDir(const Tchar* dir);

  /**
   * Set formats directory
   * @param[in] dir full directory path to folder containing the Formats.def file
   **/
  void setFormatsDir(const Tchar* dir);


  /**
   * Set dead pixel directory
   * @param[in] dir full directory path to folder containing the deadpixels file
   **/
  void setDeadPixelDir(const Tchar* dir);
  

  /**
   * Get calibration directory
   * @return full directory path to folder containing calibration files
   **/
  const Tchar* getCalibrationDir();

  /**
   * Get formats directory
   * @return full directory path to folder containing the Formats.def file
   **/
  const Tchar* getFormatsDir();
  
  /**
   * Get dead pixel directory
   * @return full directory path to folder containing dead pixel files
   **/
  const Tchar* getDeadPixelDir();

  /**
  * Check existence of calibration file set.
  * @param[in] serial Serial number of device
  * @return Returns NULL-pointer if no file is missing, otherwise path of missing files as comma separated list. Free returned pointer with delete[].
  */
  Tchar* checkCalibration(unsigned long serial);

  /**
   * Check available optics for a specific device
   * @param[in] serial serial number of device
   * @return vector of available optics (fov)
   */
  const IRArray<IROptics>* getAvailableOptics(unsigned long serial);

  /**
  * Get (concat) path and name of configuration file
  * @param[out] Path of configuration file
  * @param[in] directory Directory of configuration file
  * @param[in] maxLen Maximum character length of path parameter
  * @param[in] fileName Name of configuration file
  * @param[in] extension Extension of configuration file
  */
  static bool createConfigFilepath(Tchar* path, const Tchar* directory, short maxLen, const Tchar* fileName, const Tchar* extension);

  /**
  * Generate XML configuration for a specific device
  * @param[in] serial Serial number of device
  * @return text content of standard configuration file
  */
  IRArray<Tchar> generateConfiguration(unsigned long serial);

  /**
   * Check for Internet access to calibration files
   * @return availability flag
   */
  static bool isOnlineCalibrationRepoAccessible();

  /**
   * Download calibration files for a specific serial number
   * @param serial Serial number of device
   */
  bool downloadCalibration(unsigned long serial);

  /**
   * ONLY LINUX: Copy calibration files from local device, e.g., USB stick
   * @param[in] serial serial number of device for which calibration files are to be found
   * @param[in] srcDir source directory to search for calibration files
   * @return success of search and copy operation
   */
  bool copyCalibrationFromLocalRepo(unsigned long serial, const char* srcDir);

  /**
  * Determine serial number of attached device(s)
  * @param[in] serial Serial number (pass 0 to search for serial of an attached device, pass serial to search for a specific device).
  * @param[in] skip Skips the first n results. Use this to detect multiple devices.
  * @return success flag
  */
  static bool findSerial(unsigned long &query, unsigned int skipNResults = 0);

private:


  void init(const Tchar* caliPathDefault, const Tchar* formatsPathDefault);

  static bool downloadTarget(Tchar* listOfMissingFiles, unsigned long serial, const Tchar* targetDir);

  bool checkCaliFiles(const Tchar* CaliDirectory, int SerialNumber, Tchar* ListOfMissingFiles, int* Maxlen, const Tchar* configPattern, const Tchar* caliPattern, const Tchar* kennliniePattern, const Tchar* separator);

  Tchar* _pathCali;

  Tchar* _pathFormats;

  Tchar* _pathDeadPixels;

  Tchar* _framerateText;
  
  IRArray<IROptics> _optics;

  static IRCalibrationManager* _this;
};

}

#endif // IRCALIBRATIONMANAGER_H

This is the IRArray.h file:

#include <cstddef>
#include <stdexcept>
#include <sstream>

namespace evo
{

/**
 * @class IRArray
 * @brief C-Array wrapper for handle size, copy and memory
 * @author Helmut Engelhardt (Evocortex GmbH)
 */
template <class T>
class IRArray
{
private:
    //Array pointer
    T* _data;

    //Size of array
    std::size_t _size;
public:


   /**
   * Initialize array with given size
   * @param[in] size Size of array
   */
    IRArray(std::size_t size);

    /**
     * Initialize array with given size and data.
     * @param[in] size Size of array
     * @param[in] data Pointer to array to copy from. Has to be at least the given size!
     */
    IRArray(std::size_t size, const T* const data);

    /**
     * Copy constructor to copy given IRArray
     * @param[in] obj IRArray to copy
     */
    IRArray(const IRArray<T> &obj);

    /**
     * Deconstructor. Handles deletion of array
    */
    ~IRArray();

    /**
     * Assignment operator for copy IRArray
     * @param[in] obj IRArray to copy
     */
    IRArray<T>& operator=(const IRArray<T>& obj);
    
    IRArray<T>& operator=(IRArray<T>&& obj);

    /**
     * Index operator. Throws std::out_of_range if index out of range.
     * @param[in] index Index of required data
     */
    T& operator[](const std::size_t index);

    /**
     * Const index operator. Throws std::out_of_range if index out of range.
     * @param[in] index Index of required data
     */
    const T& operator[](const std::size_t index) const;

    /**
     * Returns size of array
     * @return Size of array
     */
    std::size_t size() const;

    /**
     * Returns pointer to array
     * @return Array pointer
     */
    T* const data() const;
};

} //namespace evo

template <class T>
evo::IRArray<T>::IRArray(std::size_t size)
{
    _size = size;
    if(_size > 0)
    {
        _data = new T[_size];
    }
    else
    {
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>::IRArray(std::size_t size, const T* const data)
{
    _size = size;
    if(_size > 0)
    {
        _data = (T*)(new char[size * sizeof(T)]);
        std::copy(data, data + _size, _data);
    }
    else
    {
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>::IRArray(const evo::IRArray<T> &obj) : IRArray(obj._size, obj._data)
{
}

template <class T>
evo::IRArray<T>::~IRArray()
{
    if(_data != nullptr)
    {
        delete[] _data;
        _data = nullptr;
    }
}

template <class T>
evo::IRArray<T>& evo::IRArray<T>::operator=(const evo::IRArray<T>& obj)
{
    IRArray<T> tmp(obj);
    _size = tmp._size;
    _data = tmp._data;

    tmp._size = 0;
    tmp._data = nullptr;
    return *this;
}

template <class T>
evo::IRArray<T>& evo::IRArray<T>::operator=(evo::IRArray<T>&& obj)
{
    _size = obj._size;
    _data = obj._data;

    obj._size = 0;
    obj._data = nullptr;
    return *this;
}

template <class T>
T& evo::IRArray<T>::operator[](const std::size_t index) 
{ 
    if (index < 0 || index >= _size) 
    { 
        std::stringstream ss;
        ss << "Index " << index << " out of range. [0.." << _size << "[";
        throw std::out_of_range(ss.str());
    }
    return _data[index]; 
}

template <class T>
const T& evo::IRArray<T>::operator[](const std::size_t index) const
{
    if (index < 0 || index >= _size) 
    {
        std::stringstream ss;
        ss << "Index " << index << " out of range. [0.." << _size << "[";
        throw std::out_of_range(ss.str());
    }
    return _data[index];
}

template <class T>
std::size_t evo::IRArray<T>::size() const
{
    return _size;
}

template <class T>
T* const evo::IRArray<T>::data() const
{
    return _data;
}

Initially I wrote this code:

String^ GenerateConfiguration(unsigned long serial)
{
    try
    {
        
        evo::IRArray<Tchar> result = _nativeManager->generateConfiguration(serial);
        Tchar* nativeData = result.data();

        return gcnew String(nativeData);
    }
    catch (const std::exception& ex)
    {
        throw gcnew Exception(gcnew String(ex.what()));
    }
    catch (...)
    {
        throw gcnew Exception("An unknown error occurred.");
    }
}

But I have always errors. So I reduce the code to this version but the problems persist.

String^ GenerateConfiguration(unsigned long serial)
{
    try
    {
        evo::IRArray<Tchar> result = _nativeManager->generateConfiguration(serial);
        return gcnew String("nativeData");
    }
    catch (const std::exception& ex)
    {
        throw gcnew Exception(gcnew String(ex.what()));
    }
    catch (...)
    {
        throw gcnew Exception("An unknown error occurred.");
    }
}

These are the errors:

_CrtlsValidHeapPointer(block)

is_block_type_valid(header->_block_use)

It's finish into a System.AccessViolationException in the IRArray<T>::~IRArray() at this line _data = nullptr;

Share Improve this question asked Nov 20, 2024 at 15:24 th3g3ntl3manth3g3ntl3man 2,1066 gold badges33 silver badges57 bronze badges 7
  • It sounds like you're corrupting memory, that won't fly in a managed language like C++/CLI. – Blindy Commented Nov 20, 2024 at 15:31
  • @Blindy How am I corrupting the memory? I am simply calling a method defined into the library. – th3g3ntl3man Commented Nov 20, 2024 at 15:32
  • You just answered your own question! – Blindy Commented Nov 20, 2024 at 15:38
  • @Blindy Ok but I don't have access to the library... I don't understand how it's possible, only this method gives problems, the others have been successfully integrated! – th3g3ntl3man Commented Nov 20, 2024 at 15:40
  • Are you saying memory corruption in one function is impossible because the others don't corrupt memory as well? What exactly is the point you're trying to make here? – Blindy Commented Nov 20, 2024 at 15:51
 |  Show 2 more comments

1 Answer 1

Reset to default 3

So long story short, memory corruption. In fact even the little code you've shown is so badly written that I spotted one memory corruption spot at a glance already:

template <class T>
evo::IRArray<T>& evo::IRArray<T>::operator=(const evo::IRArray<T>& obj)
{
    IRArray<T> tmp(obj);
    _size = tmp._size;
    _data = tmp._data;

    tmp._size = 0;
    tmp._data = nullptr;
    return *this;
}

This code makes a copy of the const input array and steals its data pointer (the copy's, not the original's, because it can't write to the original). You then have both this and the original array both holding the same data pointer, both fighting over it to delete it in the destructor.

evo::IRArray<Tchar> result = _nativeManager->generateConfiguration(serial);

This line then triggers the copy code above, then the destructor triggers because you're dropping the temporary copy deleting the memory pointer. Then the end of the function comes and result is getting destroyed and it now has an invalid pointer which then triggers an access violation exception.

发布评论

评论列表(0)

  1. 暂无评论