cancel
Showing results for 
Search instead for 
Did you mean: 

STM Compiler & & Operator

CYBR
Associate II

I am trying to understand what I am doing wrong here. The following image was captured during a debug session to show strange behaviour.

2024-06-07_14-48-35.png

In the If statement ap->enable and ap->active are both true, but ap->relay_map is 0, as shown on the right, so this should evaluate to false. So why does the processor execute the statement within the brackets (shown by the green highlight) since the If fails? It actually crashes the processor because the index evaluates to -1 which is out of bounds of the relays array.

1 ACCEPTED SOLUTION

Accepted Solutions

I have managed to prove that although the debugger actually looks like it steps to that line under these particular circumstances, in fact it does not execute the statement it steps to.

I put a line in between to turn on the LED. It steps to that line 10 below, but doesn't execute it, the LED does not turn on.

So apologies for wasting everyone's time. This is just an artefact of the debugger operation and not real.

 

 

	    	for(ai=0;ai<(sizeof(Alarms)/sizeof(AlarmType *));ai++)
	    	{
	    		//this process effectively does an OR, so multiple alarms can share one relay
	    		ap=Alarms[ai];
	    		if(ap->enable == true)
	    			if(ap->active == true)
	    			{
	    				if(ap->relay_map > 0)
						{
		    				HAL_GPIO_WritePin(GPIOC, LED_USER2_Pin, GPIO_PIN_RESET); //Turn Alarm LED on
							relays[ap->relay_map-1].relay_state=true;
						}
	    			}
	    	}

 

View solution in original post

10 REPLIES 10
LCE
Principal

I absolutely agree, this should work.

But you are working with an OS, could it be that some other task jumps inbetween?

Just for testing, what if you put if(ap->relay_map > 0) directly before setting relay_state = true ?

And for comlpleteness it would be nice to actually tell us which compiler and version you are actually using.

AScha.3
Chief II

Maybe - you should tell also, on which cpu and (if applicable ) d-cache used and INT or DMA ... ?

If you feel a post has answered your question, please click "Accept as Solution".

Any code we can't see to the right of the if?

Can you printf the values seen here?

Is optimization on or off? Does that change behavior?

An STM32F746 ?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
unsigned_char_array
Senior III

There are several ways this can happen (it has happened to me too):

  1. you have a compilation/linker error and didn't see it. Debugging still starts, but it loads the old binary: the source code doesn't match the elf file/ROM
  2. you modified code while debugging: the source code doesn't match the elf file/ROM
  3. something went wrong in the setup of your debug session and it didn't flash but still loaded the debugger: the ROM doesn't match the elf file/source code
  4. optimization. It reaches the breakpoint but doesn't actually execute it, or it really does execute and it should(for instance the if statement is merged with a later condition).
  5. racing condition/synchronization problem. when you reached the breakpoint the variable has already been changed in an interrupt or different thread.
  6. DMA or peripheral writes to memory
  7. stack overflow or buffer overflow has corrupted data
  8. instruction pointer corruption
  9. some macro screws everything up, you are not reading the actual preprocessed code the compiler sees. Macros are basically just text substitution and therefore have many pitfalls.
  10. very very unlikely (hasn't happened to me as far as I know): broken CPU, broken memory or broken compiler/linker.

I suggest turning off optimizations. Playing with stack size. Investigate timing of the problem (perhaps the crash coincides with a specific event and is correlated with it). Enable all warnings and change your code until you get 0 warnings. And add some sanity check to prove it actually loaded the latest code (delete build artifacts and add a print statement somewhere).

 

Comparing a boolean to true is redundant.

 

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

Thanks for all the contributions. Let me try to answer each question.

Compiler version is 1.15.0

Processor/board is STM32H735G-DK

No INT, but 2 DMA streams for ADC1 and ADC3.

Pretty sure Optimization is on, but not experienced enough to know yet how to turn it off.

I have this section protected from the other two tasks which can modify these values by Mutexes.

I modified the code in case after 30 years of writing in C I misunderstood how && works. I split it up as shown in the following. Behaviour does not change. For iterations through the loop where either enable or active are false, it does not do the relay_map test. But if these are true, it appears to execute the relays[... statement even though relay_map is set to zero.

The full task is

	for(;;)
	{
	    if ((osMutexAcquire(Alarm_Relay_Dyn_MutexHandle, mutexTWO_TICK_DELAY) == osOK) && (osMutexAcquire(Alarm_Relay_Stat_MutexHandle, mutexTWO_TICK_DELAY) == osOK))
	    {
	    	for (ai=0;ai<8;ai++)
				relays[ai].relay_state=false;

	    	for(ai=0;ai<(sizeof(Alarms)/sizeof(AlarmType *));ai++)
	    	{
	    		//this process effectively does an OR, so multiple alarms can share one relay
	    		ap=Alarms[ai];
	    		if(ap->enable == true)
	    			if(ap->active == true)
	    			{
	    				if(ap->relay_map > 0)
						{
							relays[ap->relay_map-1].relay_state=true;
						}
	    			}
	    	}
			osMutexRelease(Alarm_Relay_Dyn_MutexHandle);
			osMutexRelease(Alarm_Relay_Stat_MutexHandle);
	    	for (ai=0;ai<8;ai++)
	    	{
	    		rp=&relays[ai];

	    	}

	    }
	  osDelay(1000);
	}

No apparent compilation link errors.

I know that comparing a boolean to true is redundant. I added that in case it made a difference.

I cannot prove that it is actually executing that code line, because I don't know how to look at that memory location to see if it is being written to. But the debugger certainly steps there. It may all be just a case of the debugger stepping to a line it doesn't actually execute. I have seen it do that a lot.

I suspect the crash was coincidental, and I have yet to find the reason for that.

I will try playing with some of the things you have suggested.

H735...

So turn off (or not enable in Cube) D-cache , just to be sure, its not about caching. (for test)

Optimizer usually working perfect, so no need to set to zero. (but try...)

If you feel a post has answered your question, please click "Accept as Solution".

@AScha.3 wrote:

H735...

So turn off (or not enable in Cube) D-cache , just to be sure, its not about caching. (for test)

 


Good one! D-cache can cause a lot of issues if not configured or used correctly (sometimes it needs to be flushed/invalidated). Disabling it is a good way to check.

 


@AScha.3 wrote:

Optimizer usually working perfect, so no need to set to zero. (but try...)


My point about the optimizer wasn't that it was buggy, but that it can change the symptoms of bugs. Changing optimization settings can expose bugs or mask the effects of bugs.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

@CYBR wrote:

Processor/board is STM32H735G-DK


I have the same board on my desk. Do you have any external hardware? If you upload your (simplified) project I can see if I can replicate your issue.

 


@CYBR wrote:

Pretty sure Optimization is on, but not experienced enough to know yet how to turn it off.


right click your project in project explorer or click "Project" in menubar
Then go to Properties/C C++ Build/Settings/MCU GCC Compiler/Optimization/Optimization level
(In Settings select your build configuration(target), probably "Debug")

 


@CYBR wrote:

I cannot prove that it is actually executing that code line, because I don't know how to look at that memory location to see if it is being written to. But the debugger certainly steps there. It may all be just a case of the debugger stepping to a line it doesn't actually execute. I have seen it do that a lot.


You can try opening disassembly window and step through machine code. You can also inspect memory in memory viewer window.
You can enable stack overflow detection option in FreeRTOS configuration, although it doesn't catch all types of stack overflow.

Another idea is to copy ap->relay_map to a local variable and then use that in the if and in the array brackets. It should prevent many causes of the value changing in between checking the value and using the value.

Kudo posts if you have the same problem and kudo replies if the solution works.
Click "Accept as Solution" if a reply solved your problem. If no solution was posted please answer with your own.

+1 The optimizer can rearrange the code and give non-linear behaviour, so there's less/no one-to-one relationship between the C code and the line/address meta data with the assembler that performs it. Data held in registers will not be visible in memory view.

Thus why I said to Print It Out, to force the code to express what IT'S SEEING

A disassembly of the code would also be instructive.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..