Reputation: 7769
I'm updating an old C++ DLL project. For one of the exported functions there's
BSTR __stdcall j2cs( const long lJulian, int bDMY, BSTR sDelim ) {
USES_CONVERSION;
int iDay, iMonth;
long lYear;
char chDate[20];
char chInt[10];
char * cDelim = W2A( sDelim );
The W2A
macro is defined as
#define W2A(lpw) (\
((_lpw = lpw) == NULL) ? NULL : (\
(_convert = (static_cast<int>(wcslen(_lpw))+1), \
(_convert>INT_MAX/2) ? NULL : \
ATLW2AHELPER((LPSTR) alloca(_convert*sizeof(WCHAR)), _lpw, _convert*sizeof(WCHAR), _acp))))
Visual Studio 2019 flags the W2A macro with the following compiler warning
Warning C6255 _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead.
How would I make the suggested change to the W2A macro? Or should I just ignore the warning?
LATER
My USES_CONVERSION macro is defined as
#define USES_CONVERSION int _convert = 0; (_convert); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
Upvotes: 0
Views: 1025
Reputation: 17613
Whether you should change from _alloca()
to _malloca()
would seem to be primarily dependent on the size of the memory being allocated since the amount of memory being allocated must fit on the stack in order to be successful.
This would seem to depend not only on the current size of the stack but also how much more of the stack will be used by functions that are called.
My rule of thumb is if it's a small allocation, _alloca()
is probably safe. The difficulty with using _alloca()
is the exception that can be raised should it fail.
See this Microsoft documentation on _alloca()
, https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/alloca?view=msvc-170
The _alloca routine returns a void pointer to the allocated space, which is suitably aligned for storage of any type of object. If size is 0, _alloca allocates a zero-length item and returns a valid pointer to that item.
A stack overflow exception is generated if the space can't be allocated. The stack overflow exception isn't a C++ exception; it's a structured exception. Instead of using C++ exception handling, you must use Structured exception handling (SEH).
About _malloca()
_malloca()
seems to be a Microsoft Visual Studio function and it is not the same as _alloca()
but seems to have logic to either use _alloca()
if there is sufficient room on the stack or to use malloc()
to allocate memory on the heap if there is not sufficient room on the stack.
The _malloca()
function requires the use of the _freea()
function to properly handle the pointer to the allocated memory.
From Microsoft Learn at URL https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/malloca?view=msvc-170
Allocates memory on the stack. This function is a version of
_alloca
with security enhancements as described in Security features in the CRT.Return value
The
_malloca
routine returns a void pointer to the allocated space, which is suitably aligned for storage of any type of object. If size is 0,_malloca
allocates a zero-length item and returns a valid pointer to that item.If size is greater than
_ALLOCA_S_THRESHOLD
, then_malloca
attempts to allocate on the heap, and returns a null pointer if the space can't be allocated. If size is less than or equal to_ALLOCA_S_THRESHOLD
, then_malloca
attempts to allocate on the stack, and a stack overflow exception is generated if the space can't be allocated. The stack overflow exception isn't a C++ exception; it's a structured exception. Instead of using C++ exception handling, you must use Structured exception handling (SEH) to catch this exception.Remarks
_malloca
allocates size bytes from the program stack or the heap if the request exceeds a certain size in bytes given by_ALLOCA_S_THRESHOLD
. The difference between_malloca
and_alloca
is that_alloca
always allocates on the stack, regardless of the size. Unlike_alloca
, which doesn't require or permit a call to free to free the memory so allocated,_malloca
requires the use of_freea
to free memory. In debug mode,_malloca
always allocates memory from the heap.
About Structured Exception Handling
From https://learn.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-170
Structured exception handling (SEH) is a Microsoft extension to C and C++ to handle certain exceptional code situations, such as hardware faults, gracefully. Although Windows and Microsoft C++ support SEH, we recommend that you use ISO-standard C++ exception handling in C++ code. It makes your code more portable and flexible. However, to maintain existing code or for particular kinds of programs, you still might have to use SEH.
Upvotes: 0
Reputation: 38824
W2A
can't be changed to using malloc
. You have to add free
in all places where W2A
used. The ideal alternative is std::vector
in place of _alloca
.
Update the macro USES_CONVERSION
, so it contains std::vector<WCHAR> _buffer;
and update the macro W2A
:
#define USES_CONVERSION int _convert = 0; (_convert); std::vector<WCHAR> _buffer; (_buffer); UINT _acp = ATL::_AtlGetConversionACP() /*CP_THREAD_ACP*/; (_acp); LPCWSTR _lpw = NULL; (_lpw); LPCSTR _lpa = NULL; (_lpa)
#define W2A(lpw) (\
((_lpw = lpw) == NULL) ? NULL : (\
(_convert = (static_cast<int>(wcslen(_lpw))+1), \
(_convert>INT_MAX/2) ? NULL : \
(_buffer.resize(_convert), \
ATLW2AHELPER((LPSTR) _buffer.data(), _lpw, _convert*sizeof(WCHAR), _acp)))))
Upvotes: 1