Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys/tsrb: bug fix for tsrb_get_one() #11624

Merged
merged 1 commit into from Jun 5, 2019
Merged

Conversation

korotkoves
Copy link
Contributor

Contribution description

Fixes bug for getting 0xFF byte from ring buffer.
When we want to get such byte as char (signed type), it returns -1 (means buffer is empty).

Testing procedure

Put 0xFF byte to buffer and try to get it with tsrb_get_one()

@jcarrano jcarrano added the Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) label Jun 4, 2019
smlng
smlng previously requested changes Jun 4, 2019
@@ -32,7 +32,7 @@ static char _pop(tsrb_t *rb)
int tsrb_get_one(tsrb_t *rb)
{
if (!tsrb_empty(rb)) {
return _pop(rb);
return (unsigned char)_pop(rb);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me the problem lies in mixing error return codes with values. A better solution would be to change the signature of the function into: int tsrb_get_one(tsrb_t *rb, char *dst). Also the same problem is otherwise with tsrb_get() below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with changing the signature of the API-facing tsrb_get_one() / tsrb_get(). Rather, _pop()'s return value should just be cast to unsigned char. Since sizeof(unsigned char) < sizeof(int) on all of our platforms, this is acceptable and does not mix error return codes with values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still looks wrong to me bc it uses char not unsigned char when adding stuff also the buffer is char. It just does not look really (type) safe to me - I would use uint8_t to make it explicit.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO casting to unsigned char is the best option here. It is what getchar is doing, so can be called ideomatic C.
Also we might get away with calling this a bugfix, as the documentation clearly states that it returns the byte as >= 0. Now that I think of it, the cast must have been my initial intention anyways.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this still looks wrong to me bc it uses char not unsigned char when adding stuff also the buffer is char. It just does not look really (type) safe to me - I would use uint8_t to make it explicit.

In my opinion, we should focus on fixing the bug first, than we can discuss API changes for type safeness. The bug is fixable without an API change, so we should do that first, then do an API change if necessary. This not only makes the merge of this bug fix faster, but also allows for a better understanding of the thought process of the API change when looking at the code's history.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smlng are you fine with this fix for now, and we revisit the API later?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but it should not be that much later.


Another idea for a fix:

Documentation states, that this assumes a single producer and consumer scenario, right? So actually there is no need to return -1 on error but rather change the function to char tsrb_get_one() and the consumer MUST call tsrb_empty before access on its own otherwise the consumer might get an old/invalid value. This works because there is only one consumer hence there can be no other consumer manipulating the reads.

Still it might be sensible to change every char to unsigned char anyway.

@miri64
Copy link
Member

miri64 commented Jun 4, 2019

(reminder to self: there should be a unittest for tsrb)

@miri64
Copy link
Member

miri64 commented Jun 5, 2019

Did it in #11632.

@kaspar030
Copy link
Contributor

This problem also popped up in #9869.

@smlng smlng dismissed their stale review June 5, 2019 09:40

won't block bugfix

@miri64
Copy link
Member

miri64 commented Jun 5, 2019

The problem now is, that it might fix for \xff, but now the result is not comparable to what you put into the ring buffer. If you e.g. put '\xdb' in the buffer, tsrb_get_one() will get you an integer 219 (0x000000db), which will yield false when you compare '\xdb' == 219 without any cast.

@miri64
Copy link
Member

miri64 commented Jun 5, 2019

I guess long-term we need to do an API change, but I'd vote rather for going from char to uint8_t.

Copy link
Member

@miri64 miri64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK for this change however, though the values are not comparable directly now, it fixes that a valid output (\xff) is interpreted as an error.

@miri64 miri64 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Jun 5, 2019
@miri64 miri64 merged commit 8c5433d into RIOT-OS:master Jun 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants