Coding - Fix critical CodeQL static analysis warnings (#1074)

Interface_ParamSet:
- Eliminate use-after-free in Append() by deleting old buffer through
  a temp variable after reassigning the member pointer (CodeQL #5132/#2684)

delabella.cpp:
- Fix upcast array pointer arithmetic by parenthesizing cast to ensure
  pointer arithmetic uses derived class (Vert) size rather than base
  class (DelaBella_Vertex) size (CodeQL #5131)

NCollection_SparseArrayBase:
- Rework to replace virtual dispatch (createItem/destroyItem/copyItem)
  with function pointers passed as arguments to protected methods
- Store only DestroyItemFunc in base class to enable safe cleanup
  in destructor without virtual dispatch
- Pass CreateItemFunc and CopyItemFunc as arguments with zero
  per-instance storage overhead
- Move Clear() and UnsetValue() from base public API to protected
  clearItems()/unsetValue() with function pointer parameters;
  template class provides public wrappers
- Remove vtable entirely (no virtual methods remain)
- This eliminates the pure virtual call during base class destruction
  (CodeQL #5012)

AdvApp2Var_MathBase:
- Rewrite comparison to avoid potential signed integer overflow:
  *ncfnew + 1 > ncut becomes *ncfnew >= ncut (CodeQL #2692)
This commit is contained in:
Pasukhin Dmitry
2026-02-13 08:48:17 +00:00
committed by GitHub
parent 833c86f176
commit 56e162c480
6 changed files with 118 additions and 104 deletions
@@ -24,16 +24,30 @@
* Base class for NCollection_SparseArray;
* provides non-template implementation of general mechanics
* of block allocation, items creation / deletion etc.
*
* Type-specific item operations (construction, destruction, copy)
* are provided by the derived template class via function pointers
* passed as arguments to the protected methods.
*/
class NCollection_SparseArrayBase
{
public:
//!@name Type-independent public interface
//!@name Function pointer types for type-specific item operations
//!@{
//! Clears all the data
Standard_EXPORT void Clear();
//! Copy-construct a new item at theAddress from theOther
using CreateItemFunc = void (*)(void* theAddress, void* theOther);
//! Destroy the item at theAddress
using DestroyItemFunc = void (*)(void* theAddress);
//! Copy-assign the item at theAddress from theOther
using CopyItemFunc = void (*)(void* theAddress, void* theOther);
//!@}
public:
//!@name Type-independent public interface
//!@{
//! Returns number of currently contained items
size_t Size() const noexcept { return mySize; }
@@ -41,10 +55,6 @@ public:
//! Check whether the value at given index is set
Standard_EXPORT bool HasValue(const size_t theIndex) const;
//! Deletes the item from the array;
//! returns True if that item was defined
Standard_EXPORT bool UnsetValue(const size_t theIndex);
//!@}
private:
@@ -180,18 +190,23 @@ private:
protected:
// Object life
//! Constructor; initialized by size of item and of block (in items)
NCollection_SparseArrayBase(size_t theItemSize, size_t theBlockSize) noexcept
//! Constructor; initialized by size of item, block size, and item destructor function.
//! @param theDestroyItem is stored to enable proper item destruction in the base destructor
NCollection_SparseArrayBase(size_t theItemSize,
size_t theBlockSize,
DestroyItemFunc theDestroyItem) noexcept
: myItemSize(theItemSize),
myBlockSize(theBlockSize),
myNbBlocks(0),
mySize(0),
myData(nullptr)
myData(nullptr),
myDestroyItem(theDestroyItem)
{
}
//! Destructor
virtual ~NCollection_SparseArrayBase() { Clear(); }
//! Destructor; properly destroys all items and frees all memory.
//! Uses the stored DestroyItemFunc, so no virtual dispatch is needed.
~NCollection_SparseArrayBase() { clearItems(myDestroyItem); }
protected:
// Data access interface for descendants
@@ -219,48 +234,53 @@ protected:
+ myItemSize * (theIndex % myBlockSize);
}
//! Set a value to the specified item; returns address of the set item
Standard_EXPORT void* setValue(const size_t theIndex, void* const theValue);
//! Clears all items and frees all memory.
//! @param theDestroyItem function to call destructor on each item
Standard_EXPORT void clearItems(DestroyItemFunc theDestroyItem);
//! Deletes the item at theIndex from the array;
//! returns True if the item was defined.
//! @param theDestroyItem function to call destructor on the item
Standard_EXPORT bool unsetValue(const size_t theIndex, DestroyItemFunc theDestroyItem);
//! Set a value to the specified item; returns address of the set item.
//! @param theCreateItem function to copy-construct a new item
//! @param theCopyItem function to copy-assign an existing item
Standard_EXPORT void* setValue(const size_t theIndex,
void* const theValue,
CreateItemFunc theCreateItem,
CopyItemFunc theCopyItem);
//! Copy contents of theOther to this;
//! assumes that this and theOther have exactly the same type of arguments
Standard_EXPORT void assign(const NCollection_SparseArrayBase& theOther);
//! assumes that this and theOther have exactly the same type of arguments.
//! @param theCreateItem function to copy-construct a new item
//! @param theDestroyItem function to call destructor on an item
//! @param theCopyItem function to copy-assign an existing item
Standard_EXPORT void assign(const NCollection_SparseArrayBase& theOther,
CreateItemFunc theCreateItem,
DestroyItemFunc theDestroyItem,
CopyItemFunc theCopyItem);
//! Exchange contents of theOther and this;
//! assumes that this and theOther have exactly the same type of arguments
Standard_EXPORT void exchange(NCollection_SparseArrayBase& theOther) noexcept;
protected:
// Methods to be provided by descendant
//! Create new item at the specified address with default constructor
// virtual void createItem (void* theAddress) = 0;
//! Create new item at the specified address with copy constructor
//! from existing item
virtual void createItem(void* theAddress, void* theOther) = 0;
//! Call destructor to the item
virtual void destroyItem(void* theAddress) = 0;
//! Call assignment operator to the item
virtual void copyItem(void* theAddress, void* theOther) = 0;
private:
// Implementation of memory allocation/deallocation and access mechanics
//! Allocate space for at least iBlock+1 blocks
void allocData(const size_t iBlock);
//! Free specified block
void freeBlock(const size_t iBlock);
//! Free specified block, destroying all items via theDestroyItem
void freeBlock(const size_t iBlock, DestroyItemFunc theDestroyItem);
protected:
size_t myItemSize; //!< size of item
size_t myBlockSize; //!< block size (in items)
size_t myNbBlocks; //!< allocated size of blocks table
size_t mySize; //!< number of currently defined items
void** myData; //!< array of pointers to data blocks
size_t myItemSize; //!< size of item
size_t myBlockSize; //!< block size (in items)
size_t myNbBlocks; //!< allocated size of blocks table
size_t mySize; //!< number of currently defined items
void** myData; //!< array of pointers to data blocks
DestroyItemFunc myDestroyItem; //!< function to call destructor on items
};
#endif