This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Casting Char Pointers to Other Data Types

I just found an insidious and disconcerting characteristic of the uVision3 ARM compiler V3.12a. I have inherited C code to migrate to the ARM processor. This C code uses unsigned char pointers quite liberally to pass the address of data back and forth. The code, of course, casts these generic unsigned char pointers to various data types to access the underlying data.

I have found that if the unsigned char point happens to be pointing at a odd address and it is cast to a short type pointer (e.g., "*(SHORT*)p"), the compiler will resolve the address the previous even address. For a simplistic example, if the address of unsigned char *p happens to be 0x5 and the following code is executed:

	unsigned char	*p;
	...
	*(unsigned short*)p = 0;

rather than address 0x5 and 0x6 being set to zero as one would have expected, address 0x04 and 0x05 are set to zero and address 0x06 is left unchanged.

The same affect is demonstrated if, in the above example, the unsigned char pointer "p" is cast to an unsigned int, except is this case the compiler removes bits 0 and 1 from the address so that it is looking at divisible-by-four address. You could end up unintentionally nailing more nearby data this way.

If you are lucky and the pointer "p" lies on an even address boundary for short type casts of char pointers, the code works just fine, but odd address boundaries definitely are going to cause problems. Similar logic applies to larger standard data types. (Fortunately the code base does no casting to structure pointers, so that is not a problem for me now, but it may be a problem, too).

As I stated, this is inherited code and a major re-write to change the way pointers are deployed is simply not an option. Are there any other ideas out there? I know I can replace every pointer cast to other than an unsigned char with a function call to read or write the data, but frankly unless there is an intuitively obvious solution I'm not seeing, this looks like a huge hole in the compiler logic. Is there any hope for my faith in the Keil folks?

Thanks for any encouragement,
Doug

Parents
  • "The casts override the compiler's tracking of types and their alignment requirements. That is, after all, exactly what a C cast does. It tells the compiler, "I'm the programmer; I know what I'm doing; do what I say". If the programmer is doing the wrong thing with his casts, it's hardly the compiler's fault.

    Misalignment detection is handed by the memory subsystem on the ARM, rather than by the core itself. If your ARM has ARM's MMU or "Memory Protection Unit" (MPU), then those peripherals will generate an interrupt to the core when they detect a misaligned transfer. You could write an interrupt handler to detect this condition, do a couple of aligned transfers, and patch the data back together (just as x86s or PPC does in hardware). But of course you'll lose a fair amount of speed if the misaligned accesses are common. On the other hand, this solution will cover all of the uses."

    However, it appears that the compiler is not blindly obeying the programmer when he uses a cast, instead it is 'correctly' aligning the pointer to prevent an alignment exception occurring. The result of this is that memory is being silently trashed. In my opinion this is undesirable - I'd far rather my program crashed straight away than ran incorrectly.

Reply
  • "The casts override the compiler's tracking of types and their alignment requirements. That is, after all, exactly what a C cast does. It tells the compiler, "I'm the programmer; I know what I'm doing; do what I say". If the programmer is doing the wrong thing with his casts, it's hardly the compiler's fault.

    Misalignment detection is handed by the memory subsystem on the ARM, rather than by the core itself. If your ARM has ARM's MMU or "Memory Protection Unit" (MPU), then those peripherals will generate an interrupt to the core when they detect a misaligned transfer. You could write an interrupt handler to detect this condition, do a couple of aligned transfers, and patch the data back together (just as x86s or PPC does in hardware). But of course you'll lose a fair amount of speed if the misaligned accesses are common. On the other hand, this solution will cover all of the uses."

    However, it appears that the compiler is not blindly obeying the programmer when he uses a cast, instead it is 'correctly' aligning the pointer to prevent an alignment exception occurring. The result of this is that memory is being silently trashed. In my opinion this is undesirable - I'd far rather my program crashed straight away than ran incorrectly.

Children
No data