DarrenRpi5
Posts: 1
Joined: Tue Jun 15, 2021 8:24 pm

Geany C: Code works correctly only with debugger

Tue Jun 15, 2021 8:39 pm

Hi,

I'm using a Raspberry Pi 2B to get data from a custom made PCB using the serial peripheral. I wrote the code in C using Geany. The serial frame I'm receiving on the Pi is simple; 8 bytes, 2 sets of 16 bit integers and the remaining 4 bytes being a single precision floating variable. The issue is with the floating variable. Below is the way I'm constructing the floating value (and other 16bit integers) from the bytes received.

Code: Select all

tmp  = (rx_buff[1] << 8);
			tmp |= (rx_buff[0]);	
			mtr_v[cnt] = (double)tmp/1000;
			
			tmp  = (rx_buff[3] << 8);
			tmp |= (rx_buff[2]);	
			mtr_c[cnt] = (double)tmp/10000;	
			
			 p    = (uint8_t *)&w_tmp;
			*p++  = (rx_buff[4]);
			*p++ |= (rx_buff[5]);
			*p++ |= (rx_buff[6]);
			*p   |= (rx_buff[7]);	
			mtr_w[cnt] = (double)w_tmp;
			mtr_w[cnt] *=(-1);
In this code, tmp is a 16 bit integer, mtr_v, mtr_c and mtr_w are arrays of type double, p is a uint8 pointer and w_tmp is a floating point variable. Though the values I recieve are either 16bit or float, I am casting them to double due to further processing later on. When I run the code with the debugger, everything works well without issues. When I execute the code, the values I get in 'mtr_w' doesn't makes sense. WHat should be a value of around 560.799, I'm getting 1010356.897. Again, this does not happen if I run the code with the debugger.

Any one has an idea about the reason?

Note: I don't know if it matters but I am receiving the 8 bytes continuously every 10ms.

pidiv
Posts: 39
Joined: Mon May 24, 2021 8:03 am

Re: Geany C: Code works correctly only with debugger

Wed Jun 16, 2021 10:58 am

DarrenRpi5 wrote:
Tue Jun 15, 2021 8:39 pm

Code: Select all

			 p    = (uint8_t *)&w_tmp;
			*p++  = (rx_buff[4]);
			*p++ |= (rx_buff[5]);
			*p++ |= (rx_buff[6]);
			*p   |= (rx_buff[7]);	
			mtr_w[cnt] = (double)w_tmp;
			mtr_w[cnt] *=(-1);
In this code, tmp is a 16 bit integer, mtr_v, mtr_c and mtr_w are arrays of type double, p is a uint8 pointer and w_tmp is a floating point variable. Though the values I recieve are either 16bit or float, I am casting them to double due to further processing later on. When I run the code with the debugger, everything works well without issues. When I execute the code, the values I get in 'mtr_w' doesn't makes sense. WHat should be a value of around 560.799, I'm getting 1010356.897. Again, this does not happen if I run the code with the debugger.

Any one has an idea about the reason?
I don't like the look of the *p++ |= ... stuff. You're mixing the new data with what's already in there. In a debugger, it's plausible that w_tmp would be initialised to 0, so that |= is just the same as =. But outside the debugger, w_tmp is likely to contain to garbage, and so you're mixing garbage into your result. Unless you've explicitly zero-ed w_tmp somewhere, of course...

ETA: there's a separate problem, related to aliasing... I think the compiler is entitled to assume that changes to *p cannot modify the value of w_tmp because they are of different types. I can't say I fully understand the rules. A "correct" way to do this that I have seen is to use a volatile union. Something along the lines of

Code: Select all

volatile union { float f; uint8_t b[4]; }  tmp;
memcpy(tmp.b, rx_buff+4, 4);  // or byte by byte if you prefer
mtr_w[cnt] = (double)tmp.f;
By making it volatile, you are telling the compiler that it must copy the bytes into tmp.b and then it must read tmp.f from memory. But this would be related to code generation, and isn't something that would change when running in the debugger or not.

User avatar
Paeryn
Posts: 3306
Joined: Wed Nov 23, 2011 1:10 am
Location: Sheffield, England

Re: Geany C: Code works correctly only with debugger

Wed Jun 16, 2021 4:40 pm

pidiv wrote:
Wed Jun 16, 2021 10:58 am
A "correct" way to do this that I have seen is to use a volatile union. Something along the lines of

Code: Select all

volatile union { float f; uint8_t b[4]; }  tmp;
memcpy(tmp.b, rx_buff+4, 4);  // or byte by byte if you prefer
mtr_w[cnt] = (double)tmp.f;
By making it volatile, you are telling the compiler that it must copy the bytes into tmp.b and then it must read tmp.f from memory. But this would be related to code generation, and isn't something that would change when running in the debugger or not.
You don't need to make the union volatile, C11 states that
C11 (draft) wrote: If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’).
Which to me says that if a member of a union is changed (b in this case) then reading from a different member where the two members share some part of their storage (f in this case) will see the data that was written.
She who travels light — forgot something.
Please note that my name doesn't start with the @ character so can people please stop writing it as if it does!

Heater
Posts: 18362
Joined: Tue Jul 17, 2012 3:02 pm

Re: Geany C: Code works correctly only with debugger

Wed Jun 16, 2021 5:05 pm

It is not correct to use "volatile" unless one is using it to access memory that can be read/written by something outside of C or C++. For example when accessing memory mapped registers of hardware peripherals.

In this case you are only trying to interpret data received from a serial port. No "volatile" required.

Be aware that although you may be sending 8 bytes every 10ms there is no guarantee that your code receiving that sees those 8 byte packets coming in so neatly. Basically it is receiving and endless stream of bytes. How does it know when your 8 byte data packed starts? What if it starts receiving mid-way through a packet? Then noting will make sense.

You need to add something unique to your data transmission to indicate when a packet starts. Preferably add a checksum to the end of the packet so that the receiving end can check the packet is received without error.
Memory in C++ is a leaky abstraction .

pidiv
Posts: 39
Joined: Mon May 24, 2021 8:03 am

Re: Geany C: Code works correctly only with debugger

Wed Jun 16, 2021 9:29 pm

Heater wrote:
Wed Jun 16, 2021 5:05 pm
It is not correct to use "volatile" unless one is using it to access memory that can be read/written by something outside of C or C++. For example when accessing memory mapped registers of hardware peripherals.
I don't think it has to be outside of c : could also be if the variable is modified by a signal handler, or in another thread. But yes, in this case, it's conceivable that it could be done as a register move without having to go through memory.

Heater
Posts: 18362
Joined: Tue Jul 17, 2012 3:02 pm

Re: Geany C: Code works correctly only with debugger

Wed Jun 16, 2021 11:30 pm

One should not use "volatile" for communicating between threads:

"Do not use volatile as a synchronization primitive": https://wiki.sei.cmu.edu/confluence/dis ... +primitive
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 8:29 am

Heater wrote:
Wed Jun 16, 2021 11:30 pm
One should not use "volatile" for communicating between threads:

"Do not use volatile as a synchronization primitive": https://wiki.sei.cmu.edu/confluence/dis ... +primitive
IIUC, in C++ one may use "atomic" instead of "volatile" ( #include <atomic> ), e.g. sth like atomic<bool>, atomic<int>, or perhaps atomic_bool, atomic_int. (which's actual usage is quite confusing though...)
(edited)

But what is one supposed to use in plain C instead?

OTOH, I always am using "volatile" or "volatile static" for global POSIX pthread synchronization (e.g., for semaphores to exit perpetual loops) and it always worked fine (not for realtime-critical purposes by nanoseconds so far, but Linux is not realtime-capable anyway).

Heater
Posts: 18362
Joined: Tue Jul 17, 2012 3:02 pm

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 8:50 am

dsyleixa123 wrote:
Thu Jun 17, 2021 8:29 am
But what is one supposed to use in plain C instead?
C has had atomic operations since C11.
https://riptutorial.com/c/topic/4924/atomics
https://developers.redhat.com/blog/2016 ... ics-part-1
https://www.ida.liu.se/~TDDD56/labs/Lab ... s-2018.pdf

Use a language that is safe against such race conditions.
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 8:54 am

there are no reasonable and understandable code examples in your links how to use "atomic" in ANSI C.

is #include <stdatomic.h> needed (or is that for C++)?
Just add "_Atomic" before datatype?
Is "static" absolutely necessary ?
Is it possible to initialize by declaration like usual?
And then operate with them just like with "primitive" data types (int, bool,...)?

Code: Select all

#include <stdatomic.h> // for ANSI C?
static _Atomic int myval=0;
static _Atomic bool flag=true;
//...
myval=42;
flag=false;
myval|= 7;
:?:

dbrion06
Posts: 511
Joined: Tue May 28, 2019 11:57 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 10:55 am

https://stackoverflow.com/questions/153 ... c-variable

says
static _Atomic int myval=0;
is bad....
I bet this IT links answers some of your questions

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 11:08 am

as I said, the usage of all that atomic stuff is confusing and weird and reasonable and understandable examples are missing, also in your link.
As to me, OTOH, volatile static is fine though, both for C and C++.


dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 11:55 am

still no practical useable code there how to rewrite my code example from above viewtopic.php?p=1878587#p1878587, and most of your link is about C++.

Heater
Posts: 18362
Joined: Tue Jul 17, 2012 3:02 pm

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:11 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 11:55 am
as I said, the usage of all that atomic stuff is confusing and weird and reasonable and understandable examples are missing, also in your link.
As to me, OTOH, volatile static is fine though, both for C and C++.
Except a couple of issues:
1) Using volatile is not expressing in your source code what you actually are trying to do. "Volatile" tells the reader you are talking to something outside the program, i.e. hardware. But what are actually trying to so is communicate between threads.

2) Not fine at all. Likely "undefined behaviour". Will be prone to fail in strange ways in some situations. See: https://www.iar.com/knowledge/support/t ... statement/

dsyleixa123 wrote:
Thu Jun 17, 2021 11:55 am
still no practical useable code there how to rewrite my code example from above viewtopic.php?p=1878587#p1878587, and most of your link is about C++.
See:
https://lwn.net/Articles/691128/
https://lumian2015.github.io/lockFreePr ... rency.html
https://developers.redhat.com/blog/2016 ... ics-part-1

And others around the net.

WARNING: This may require some actual reading...

Reality is that things do get complicated, confusing and failure prone when dealing with threads in C. Or threads in general for that matter. See for example "The ABA problem" : https://en.wikipedia.org/wiki/ABA_problem
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:16 pm

just please provide practical useable code how to rewrite my code example from above viewtopic.php?p=1878587#p1878587 to make that clear!
(PS, IMO "volatile" directs the program not to cache the variant (and not to optimize it away) but always to read it's actual value (which might have been changed meanwhile e.g. by another thread or task or an attached device) )

dbrion06
Posts: 511
Joined: Tue May 28, 2019 11:57 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:32 pm

Code: Select all

there how to rewrite my code example 
just ask https://www.sonarsource.com/cpp/ if your example is in C++
or
https://www.sonarsource.com/c/ if your example is in C (see ,2p s are lacking. Seem they are structured -else, would go bankrupt -

from heater post, at 2:11
WARNING: This may require some actual reading...
you answer at 2.16: I suppose you read fast
Last edited by dbrion06 on Thu Jun 17, 2021 12:35 pm, edited 1 time in total.

Heater
Posts: 18362
Joined: Tue Jul 17, 2012 3:02 pm

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:32 pm

dsyleixa123 wrote:
Thu Jun 17, 2021 12:16 pm
just please provide practical useable code how to rewrite my code example from above viewtopic.php?p=1878587#p1878587 to make that clear!
(PS, IMO "volatile" directs the program not to cache the variant but always to read it's actual value (which might have been changed meanwhile e.g. by another thread or task or an attached device) )
You opinion does not matter. What the C language defines is the important thing.

Can I suggest you read all the links given and try to figure it out yourself. Best to create a little C program with a couple of threads that you can use to experiment with what you find out.

Even if I were into spoon feeding solutions to people I have enough software problems of my own to fix today. And it's almost too hot around here to think.

If you were to show that you had put some effort in and still had problems with it I'm sure people would be more inclined to advise. Perhaps in a new thread on "C / atomics"
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:39 pm

Can I suggest you read all the links given and try to figure it out yourself.
tbh, no: too many characters :roll:
(All in those links IMO is demanding but exaggerated quibbles ;) )

just be so kind and correct my code example, would you? The best way to learn is from functioning examples (and finally you were the one who suggested atomics to the OP instead of volatile) 8-)
Last edited by dsyleixa123 on Thu Jun 17, 2021 12:42 pm, edited 1 time in total.

dbrion06
Posts: 511
Joined: Tue May 28, 2019 11:57 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:41 pm

I gave you a link which detects (and hints for correxctions) bad C and bad C++ (they do not mess up: maybe it takes time)

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:43 pm

dbrion06 wrote:
Thu Jun 17, 2021 12:41 pm
I gave you a link which detects (and hints for correxctions) bad C and bad C++ (they do not mess up: maybe it takes time)
as I said, as to my code example from above, reasonable and understandable examples are missing, also in your link, and the question was about C, not C++.

dsyleixa123
Posts: 1494
Joined: Mon Jun 11, 2018 11:22 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 12:48 pm

Heater wrote:
Thu Jun 17, 2021 12:32 pm
dsyleixa123 wrote:
Thu Jun 17, 2021 12:16 pm
(PS, IMO "volatile" directs the program not to cache the variant (and not to optimize it away) but always to read it's actual value (which might have been changed meanwhile e.g. by another thread or task or an attached device) )
You opinion does not matter. What the C language defines is the important thing.
Wikipedia wrote:In computer programming, particularly in the C, C++, C#, and Java programming languages, the volatile keyword indicates that a value may change between different accesses, even if it does not appear to be modified. This keyword prevents an optimizing compiler from optimizing away subsequent reads or writes and thus incorrectly reusing a stale value or omitting writes. Volatile values primarily arise in hardware access (memory-mapped I/O), where reading from or writing to memory is used to communicate with peripheral devices, and in threading, where a different thread may have modified a value.
nonetheless, as atomic is supposed to work better than volatile for threading, I'd gladly use it if one finally provided actual functioning code... ;)

dbrion06
Posts: 511
Joined: Tue May 28, 2019 11:57 am

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 1:39 pm

Does wikipedia state making a variable volatile avoids race conditions (nice race conditions would be a bank, where there is a thread to buy makeup with a card and another one, to buy lipstick with the same card.... wikipedia has kind of such lovely example https://de.wikipedia.org/wiki/Wettlaufsituation
usually, race conditions are more unpleasant; they sometimes happen, are difficult to reproduce and very difficult to debug).

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 29039
Joined: Sat Jul 30, 2011 7:41 pm

Re: Geany C: Code works correctly only with debugger

Thu Jun 17, 2021 3:17 pm

OK. This thread was flagged up in a report, that it had been hijacked and taken way off topic.

And I agree. The discussion about volatile etc should be elsewhere. Not only that but the insistence of one poster in people fixing up examples for him because he cannot be bothered to read the provided links is really quite stunning. Don't do that. People don't have time to spoon feed you. READ and comprehend. All the information is out there and easily found.

If you want to talk volatile, start another thread - but first read the language spec.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Working in the Application's Team.

Return to “C/C++”