Arguments not passed to function call

Go To Last Post
14 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi guys,

 

I'm experience some crazy behavior of code which is beyond my understandings. Problem is that when calling function from function and passing argument, that argument gets scrambled or not passed at all (don't know which option is going on).

Crazy about this is, that when I'm trying to change the code, sometimes it works as expected but then after changing more code, it stops working. And of course, this is really unpredictable and not depends on variable manipulation in suspect.

 

Here is the typedef and code snippet:

typedef struct {
	uint8_t		Button;
	uint8_t		ButtonState;
	uint8_t		Index;
} FncCallPayloadButton_t;

typedef struct {
	enum CS_SectionID_e	TargetSection;
	uint8_t				ActionType;
	void*				Payload;
} FncCallPayload_t;

typedef FncCallPayload_t* pFncCallPayload;

typedef uint8_t ( *pFncCS )   ( pFncCallPayload FncCallPayload );	

 

void	CS_Dummy( pFncCallPayload FncCallPayload ) {
 	CDC_SendString_P( PSTR("CS_Dummy " ) );
 	CDC_SendNumber(  ( (FncCallPayloadButton_t*) FncCallPayload->Payload )->Index );
	PrintMemory( (uint8_t*) FncCallPayload->Payload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
 }

  static uint8_t CS_Load( pFncCallPayload FncCallPayload ) {
 	CDC_SendString_P( PSTR("CS_Load" ) ); CDC_SendNewLine();

 	CDC_SendNumber(  ( (FncCallPayloadButton_t*) FncCallPayload->Payload )->Index );
	PrintMemory( (uint8_t*) FncCallPayload->Payload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );

 	FncCallPayload->TargetSection = CS_SEC_BROADCAST;
 	SetReturnSet( FncCallPayload );
 	CS_Set( CS_SET_LOAD, FncCallPayload );
 }

  void CS_CallButtonFunction( pFncCallPayload FncCallPayload ) {
  	CDC_SendString_P( PSTR("CS_CallButtonFunction" ) ); CDC_SendNewLine();

	PrintMemory( (uint8_t*) FncCallPayload->Payload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );

	CS_Dummy( FncCallPayload );

  	FncCallPayloadButton_t*	FncCallPayloadButton = (FncCallPayloadButton_t*) FncCallPayload->Payload;
  	uint8_t	BtnFncCallIndex;

  	switch ( FncCallPayloadButton->ButtonState ) {
  		case BTN_ACTION_TYPE_1CLK:
  			BtnFncCallIndex = 0;
  			break;
  		case BTN_ACTION_TYPE_2CLK:
  			BtnFncCallIndex = 1;
  			break;
  		case BTN_ACTION_TYPE_3CLK:
  			BtnFncCallIndex = 2;
  			break;
  		case BTN_ACTION_TYPE_HOLD:
  			BtnFncCallIndex = 3;
  			break;
  	}

  	BtnActions_t*	pBtnAction  = (BtnActions_t*) pgm_read_word ( &CS_Sections[ FncCallPayload->TargetSection ].BtnActions );

  	if ( pBtnAction == NULL )
  		return;

  	enum CS_SectionButtonsRef_e BtnActionRef = (enum CS_SectionButtonsRef_e) pgm_read_byte ( &CS_Sections[ FncCallPayload->TargetSection ].BtnActionsReferenceType );

  	if ( BtnActionRef == CS_SEC_BUTTON_ACTION_DISTINCT )
  		pBtnAction += FncCallPayloadButton->Index;

  	pFncCS FncCall = (pFncCS) pgm_read_word ( (pFncCS*) pBtnAction + BtnFncCallIndex );

	PrintMemory( (uint8_t*) FncCallPayload->Payload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );

   	if ( FncCall != NULL ) {
  		CS_Dummy( FncCallPayload );
    	FncCall( FncCallPayload );
  	}

  }
 

object payload is generated like this:
 

void ControlSurfaceProcessButton( uint8_t Button, uint8_t EventType ) {

	FncCallPayload_t		FncCallPayload;
	FncCallPayloadButton_t  FncCallPayloadButton;

	FncCallPayloadButton.Button		= Button;
	FncCallPayloadButton.ButtonState= EventType;

	FncCallPayload.TargetSection	= CS_SEC_FINDCONTROLTARGET;
	FncCallPayload.ActionType		= CS_ACTION_BUTTON;
	FncCallPayload.Payload			= &FncCallPayloadButton;

	CS_Action( &FncCallPayload );
}

and after call to CS_ProcessButoonFunction output is like this (don't mind garbled characters, these are not results from memory corruption but rather my lightweight int2str which takes int16 only):

CS_CallButtonFunction

0AD3: 0015 - 0E 02 02                 0  * 11 12 EB 01 EB 01
CS_Dummy 000AB

-▒55: 0015 - F0 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A

0AD3: 0015 - 0E 02 02                 0  * 11 12 EB 01 EB 01
CS_Dummy 000AB

-▒55: 0015 - F0 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A
CS_Load
000AB

-▒55: 0015 - F0 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A 1A

 

What is crazy is that after entering CS_CallButtonFunction data on argument are valid, but are not valid in functions called from here, but are still valid even after some functions has been called (which could indicate that stack corruption is not goinf on).

Currently I'm compiling with flto option, but this is also happening without flto option compilation. I've run out of ideas what could be the cause of this.

Does anybody have an idea what's going on?

 

Thanks a lot.

T.

Last Edited: Sat. Mar 26, 2016 - 11:04 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Stack overflow?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

Stack overflow?

 

I don't think so. Got stack paint and checked. at least 200 bytes free and untouched. And data are still valid in context of main caller function even after call to callee.

Last Edited: Sat. Mar 26, 2016 - 10:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is really strange, I can't explain it. Changed major function like this:

 

void ControlSurfaceProcessButton( uint8_t Button, uint8_t EventType ) {
	
	uint8_t oldSREG	= SREG;
	cli();
	
	FncCallPayload_t		FncCallPayload;
	FncCallPayloadButton_t  FncCallPayloadButton;

	FncCallPayloadButton.Button		= Button;
	FncCallPayloadButton.ButtonState= EventType;
	
	FncCallPayload.TargetSection	= CS_SEC_FINDCONTROLTARGET;
	FncCallPayload.ActionType		= CS_ACTION_BUTTON;
	FncCallPayload.Payload			= &FncCallPayloadButton;
	
 	PrintMemory( (uint8_t*) &FncCallPayloadButton, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
 	PrintMemory( (uint8_t*) &FncCallPayload - 1, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
 	PrintMemory( (uint8_t*) &FncCallPayload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
 	PrintMemory( (uint8_t*) &FncCallPayload.ActionType, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );

	SREG = oldSREG;

	CS_Action( &FncCallPayload );
}

which produces this output

 

0AD4: 0015 - 0E 02                07  ) 11 1D  z 03  z 03

0AAE: 0015 - 9D 13    D4 0A

0A00: 0015 - AB AB AB AB AB AB AB AB AB AB AB AB AB AB AB AB

0AB0: 0015 -    D4 0A

 

- First print is OK

- Second print is OK - this is the address of main structure minus one byte

- THIRD IS COMPLETELY WRONG !!!!

- Fourth is address of second element of main structure, which is one byte offset to the address of main structure

 

Why is this happenning? ISR are disabled to prevent any interrupt firing thus potentially corrupting some stack, but even without cli it behaves the same.

Strange is, that if I close some paths of other code, or change order of code block sometimes it works. But in this situation that ISR are disabled during run, I really suspect something very unusual in compiler (though I'm not so bold to accuse compiler).

Changed arduino (MICRO ATMega32u4) to different piece but it behaves the same. Two days straight trying to find a cause of this weirdness.

 

T.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Show your PrintMemory() function. It is presumably doing conversions to strings, and if e.g. string buffers aren't large enough, or some string pointer is pointing to the wrong place it might thrash memory for you.

 

Always consider that fault-seeking mechanisms might themselves cause faults.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well I pasted your code into eclipse-CDT. There's way; way too much red to get this to build; even with adding a few #defines

 

One error it found however was a missing return value in

static uint8_t CS_Load(pFncCallPayload FncCallPayload);

 

Probably doesn't explain your error though.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JohanEkdahl wrote:

Show your PrintMemory() function. It is presumably doing conversions to strings, and if e.g. string buffers aren't large enough, or some string pointer is pointing to the wrong place it might thrash memory for you.

 

Always consider that fault-seeking mechanisms might themselves cause faults.

 

It's too large to show, but believe me checked it many times for such issue. Code doesn't work even when not using PrintMemory or other "debug" functions. What's strange, that the same PrintMemory prints correct values when passing addresses around, but not this particular address. Do you see that? If there would be any corruption on stack, I presume that other calls would fail also. But this is not the case. Meanwhile I avoided this issue by using global variables like this:

 

static FncCallPayload_t			gFncCallPayload;
static FncCallPayloadButton_t	gFncCallPayloadButton;

void ControlSurfaceProcessButton( uint8_t Button, uint8_t EventType ) {
	
 	gFncCallPayloadButton.Button		= Button;
 	gFncCallPayloadButton.ButtonState= EventType;
 	
 	gFncCallPayload.TargetSection	= CS_SEC_FINDCONTROLTARGET;
 	gFncCallPayload.ActionType		= CS_ACTION_BUTTON;
 	gFncCallPayload.Payload			= &gFncCallPayloadButton;

	
   	PrintMemory( (uint8_t*) &gFncCallPayloadButton, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
   	PrintMemory( (uint8_t*) &gFncCallPayload - 1, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
   	PrintMemory( (uint8_t*) &gFncCallPayload, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );
   	PrintMemory( (uint8_t*) &gFncCallPayload.ActionType, 16, MEMORY_RAM | MEMORY_PRINT_USEPRINTABLE );

	CS_Action( &gFncCallPayload );
}

... which should be not taken as "final solution".

 

Now the code works as it should. There is something very weird going on under presumably compiler optimisation. (compiling with -fno-strict-aliasing)

For me it's just doesn't make sense. It's almost seems that code just want to pass argument through registers and not on stack, but loses content during code execution.

 

- not returning an value should not posses any issues. Not using return values anywhere (could change definitions some time, but now there is a lot of such functions)

 

T.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The ABI for GCC suggests that argument passing only resorts to the stack when there are too many arguments or the function is variadic - neither applies here so why would you expect the stack to be used? 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Indeed.  OP has gone to much effort to instrument the situation.  To me, the straightforward first step would be to examine/post .LSS fragments around the function calls in question.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

The ABI for GCC suggests that argument passing only resorts to the stack when there are too many arguments or the function is variadic - neither applies here so why would you expect the stack to be used? 

 

Hi dawson, I'm not expecting any way how to pass arguments to function calls, honestly I don't care how compiler decide to deliver. I'm just expecting 'correct' results. 
Unfortunately, I've tried now to open this code again to present more info, but now the code is working correctly. Meanwhile I made some changes to code (needed to move forward) so (if compiler confusion could be a suspect here) now code is compiled and reordered differently not exposing faulty behavior.

 

Will try to dig up some older backup version, but meanwhile, as compiler "crush" almost everything into 'main' code, do you have any suggestion how to mark-up relevant listing info? Unfortunately I'm not assembly guru. Could insert some 'nop's on relevant calls indeed.

 

T.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi dawson

clawson

 

but now the code is working correctly. Meanwhile I made some changes to code (needed to move forward) so (if compiler confusion could be a suspect here) now code is compiled and reordered differently not exposing faulty behavior.

Sounds more like a bug in your code, not the compiler. 

 

Stack overflow doesn't mean just 'stack growing too large'.  It can also mean a stack-based variable or buffer is accessed out-of-bounds.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson, I'm deep sorry for mispelling your name. My eyes are not what they're used to be anymore :( [ from the distance cl looks like d :) ]

 

joeymorin, yes I know that stack corruption could occur by many other reasons, but for my 'simple' understanding, calling PrintMemory is just call to function with different arguments (which is plain uint16_t Address) showing errorneous results only on address of particular object is very suspiscious for me. With added fact that there are just calls to PrintMemory and not any other code around... And even without PrintMemory calls and debug 'bijou' around, the parameter wasn't correctly passed outside of bound of caller function anyway. There is no other code runiing around, so it doesn't make sense for me that (PrintMemory - Byte) or (PrintMemory + Byte) shows correct part of memory but calling PrintMemory with exact position of object does not.

Last Edited: Sun. Mar 27, 2016 - 05:04 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been called worse things ;-) 

 

Like Lee I'd want to see the LSS both in the call setup stage and then in the use of the passed parameter in the called function. I'll bet this is just a problem in a debugger watch or something similar. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson, I'm deep sorry for mispelling your name. My eyes are not what they're used to be anymore :( [ from the distance cl looks like d :) ]

I only mentioned it because my eyes are terrible, too ;-)

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]