This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TI ARM C Compiler performs illegal expression simplification



Hey Guys,

I've detected a strange behavior in the TI ARM C Compiler (version 5.1.4).
It addresses the expression simplification, when compiling with optimization level 0 (-O0).

Here's the code snippet:

static unsigned char* CDECL AllocatorAdd(unsigned char* pbyData, RTS_UI32 ui32Size, RTS_RESULT *pResult)
{
	unsigned char* pbyCopiedPos = NULL;
	unsigned int uiAlignment;
	unsigned int uiDiv;

	...

	/* check size */
	if(pbyCopiedPos + ui32Size > s_pbyAllocatorEndPosition ||
		pbyCopiedPos + ui32Size <= pbyCopiedPos)
	{
		RTS_SETRESULT(pResult, ERR_NOMEMORY);
		return NULL;
	}
	
	...

The issue occurs in the size check. Because ui32Size can lead to an overflow, the second line in the if statement checks for this overflow. Actually, it's optimized away for some reason...
Here's the disassembly:

It seems, that the second check has been replaced by a check to equal zero.

However, if the check gets the following parameters, it fails, even the C code is correct:
pbyCopiedPos: 0x6003 00A0
s_pbyAllocatorEndPosition: 0x6004 FB60
ui32Size: 0xFFFF FFE8

The line with the statement "RTS_SETRESULT(pResult, ERR_NOMEMORY);" is NOT reached, although it should be.

What the hell is going on here?


Kind regards,
Michael

  • Here's the necessary part in the globals:

    static unsigned char *s_pbyAllocatorEndPosition = NULL;

    Before it's usage, the pointer is set up to the right position.

  • I interpret the C standard to say that pointer overflow is undefined behavior, which means that the sample code is not legal C.  The C standard says (in "Additive operators" [C89 3.3.6, C99 6.5.6]) that "If both the pointer operand and the result point to [..] the same [..] object [..], the evaluation shall not produce an overflow; otherwise, the behavior is undefined."  It is true that unsigned arithmetic is well-defined to wrap around, but pointers are not quite the same as an unsigned type.  The following should work as you expect:

    #include <stdint.h>
    if((uintptr_t)pbyCopiedPos + ui32Size > (uintptr_t)s_pbyAllocatorEndPosition ||
    		(uintptr_t)pbyCopiedPos + ui32Size <= (uintptr_t)pbyCopiedPos)
  • Hi  Archaeologist,

    this way it works. Thanks a lot.

    Kind regards,
    Michael