bugmagnet
bugmagnet

Reputation: 7769

How do I use _malloca instead of _alloca in Win32 C++ project?

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

Answers (2)

Richard Chambers
Richard Chambers

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

3CxEZiVlQ
3CxEZiVlQ

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

Related Questions