Skip to main content
Associate II
June 7, 2024
Solved

STM Compiler & & Operator

  • June 7, 2024
  • 10 replies
  • 6422 views

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.

    This topic has been closed for replies.
    Best answer by CYBR

    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;
    						}
    	 			}
    	 	}

     

    10 replies

    LCE
    Principal II
    June 7, 2024

    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
    Super User
    June 7, 2024

    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 on " Best Answer ".
    Tesla DeLorean
    Guru
    June 7, 2024

    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    unsigned_char_array
    Lead III
    June 7, 2024

    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."
    CYBRAuthor
    Associate II
    June 7, 2024

    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.

    AScha.3
    Super User
    June 7, 2024

    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 on " Best Answer ".