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

Misra compliance #79

Closed
wants to merge 13 commits into from
Closed

Conversation

sanderh255
Copy link

Please find my MISRA modifications in this pull request.
I've tried to stick to the MISRA issues and not change other things ;)

I'm open for discussion and/or feedback!

@@ -86,7 +102,7 @@ void putchar_(char character);
* @param format A string that specifies the format of the output
* @return The number of characters that are written into the array, not counting the terminating null character
*/
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
printf_int_t printf_(const char* format, ...) ATTR_PRINTF(1, 2);
Copy link
Owner

Choose a reason for hiding this comment

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

This is not possible. The printf() functions must be compatible with the standard library. If the MISRA standard is incompatible with using the standard library, then we have a problem.

Copy link
Author

Choose a reason for hiding this comment

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

This is not necessarily incompatible with the std lib. If you're not defining PRINTF_CUSTOM_INT_xx then printf_int_t is a plain int. For MISRA compatibility you'd define PRINTF_CUSTOM_INT_32 to make printf_int_t an int32_t.

Copy link
Owner

Choose a reason for hiding this comment

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

Ah, ok. I guess we can do something like that. But - I still have to see the literal int in the signature. So I would rather have something like:

#ifndef PRINTF_CUSTOM_INT_xx
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
#else
printf_int_t printf_(const char* format, ...) ATTR_PRINTF(1, 2);
#endif

or maybe even:

#ifndef PRINTF_CUSTOM_INT_xx
int def1
int def2
int def3
#else 
printf_int_t def1
printf_int_t def2
printf_int_t def3
#endif

Copy link
Author

Choose a reason for hiding this comment

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

I've update the header file. Is this better?

Copy link
Owner

@eyalroz eyalroz Jan 5, 2022

Choose a reason for hiding this comment

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

You'll need a new PR with whatever changes remain after my next push.

Also... what does MISRA have to say about the standard library version of these functions? I mean, they return a plain int, after all.

Copy link
Owner

Choose a reason for hiding this comment

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

Actually, I've just read the MISRA rule regarding typedefs. It says:

6.3 (adv) typedefs that indicate size and signedness should be used in place of the basic numerical types.

So, first of all, it's a "should", not a "shall" or "will". But even more importantly - the changes you propose don't bring you much closer to satisfying this rule, since the typedef you proposed indicates neither size nor signedness. I believe this advisory is about preferring int32_t, uint8_t and such over int, unsigned, char and such.

Copy link
Author

Choose a reason for hiding this comment

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

Ah ok. I'll see about that new pull request.

Basically MISRA indicates (among others) to avoid the standard library methods regarding time/date, character handling, stream operators and allocation/deallocation. It more or less recognizes one cannot do without, but discourages dependence.

More to the point, it says "For example, the essential type rules apply to the types of the arguments passed to functions specified in the standard library and to their results."

Copy link
Author

@sanderh255 sanderh255 Jan 5, 2022

Choose a reason for hiding this comment

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

Actually, I've just read the MISRA rule regarding typedefs. It says:

6.3 (adv) typedefs that indicate size and signedness should be used in place of the basic numerical types.

So, first of all, it's a "should", not a "shall" or "will". But even more importantly - the changes you propose don't bring you much closer to satisfying this rule, since the typedef you proposed indicates neither size nor signedness. I believe this advisory is about preferring int32_t, uint8_t and such over int, unsigned, char and such.

I completely agree that is what the rule is about.
That's what I'm doing by defining printf_int_t as int16_t , int32_t or int64_t. This way the return value uses a type with defined signedness and size.

Copy link
Owner

Choose a reason for hiding this comment

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

Basically MISRA indicates (among others) to avoid the standard library methods regarding time/date, character handling, stream operators and allocation/deallocation. It more or less recognizes one cannot do without, but discourages dependence.

Well, this library is about providing these same problematic functions. But - we'll see how it looks in the new PR. Closing this one for now.

@@ -261,11 +260,11 @@ static inline void out_wrapped_function(char character, void* wrapped_function,

// internal secure strlen
// @return The length of the string (excluding the terminating 0) limited by 'maxsize'
static inline unsigned int strnlen_s_(const char* str, size_t maxsize)
static inline printf_uint_t strnlen_s_(const char* str, size_t maxsize)
Copy link
Owner

Choose a reason for hiding this comment

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

Maybe I could just make it size_t?

Copy link
Author

Choose a reason for hiding this comment

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

Good suggestion, done in an additional commit.

}
return i;
}


// output the specified string in reverse, taking care of any zero-padding
static size_t out_rev_(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
static size_t out_rev_(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, printf_uint_t width, printf_uint_t flags)
Copy link
Owner

Choose a reason for hiding this comment

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

I suppose I could have a distinct type for the flag holder integer.

@@ -1055,8 +1056,9 @@ static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const
}
}
// string output
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision)) {
Copy link
Owner

Choose a reason for hiding this comment

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

Is this exactly equivalent?

What if there are no precision flags? In that case, with the new code, precision gets decremented while before it wasn't.

Copy link
Author

Choose a reason for hiding this comment

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

That is true, but precision is only used to exit the while loop, so this does not impact any functionality.

@eyalroz
Copy link
Owner

eyalroz commented Jan 3, 2022

MISRA C:2004, 6.3 - typedefs that indicate size and signedness should be used in place of the basic types

Mostly ok, but not when it comes to standard library compliance of the user-visible functions. See individual comments. Also, I might want to have more than one unsigned-int replacement, depending on the context.

MISRA C:2004, 19.10

Ok.

MISRA C++:2008, 18-0-1 - The C library shall not be used.

Can you explain the impact of this change? I think I'm ok with it, but I'm not sure I understand exactly what would happen.

MISRA C:2004, 16.9 - A function identifier shall only be used with either a preceding &, or with a parenthesized parameter list, which may be empty.

Ok.

Unmodified pointers should be const (MISRA C:2004, 16.7 )

  1. I believe you are mis-applying the rule. There is a common signature to these functions, and buffer is generally modified.
  2. You seem to have two patches with this title, one saying "revert".

MISRA C:2012, 20.1 - #include directives should only be preceded by preprocessor directives or comments

Ok.

Removed redundant cast

Ok.

Merge collapsible if statements (not strictly MISRA)

Don't have a strong opinion here; I probably separated for readability and consistency with other pieces of code earlier or below. Can you explain why you believe this is useful/important?

Rule 13.3 increment/decrement with other side effects

Generally ok, but see specific comment

@eyalroz
Copy link
Owner

eyalroz commented Jan 3, 2022

Oh, one last thing - your PR should be against the develop branch :-P

@sanderh255 sanderh255 changed the base branch from master to develop January 3, 2022 11:13
@sanderh255
Copy link
Author

Thanks for you comments, please find my responses below.

MISRA C:2004, 6.3 - typedefs that indicate size and signedness should be used in place of the basic types

Mostly ok, but not when it comes to standard library compliance of the user-visible functions. See individual comments. Also, I might want to have more than one unsigned-int replacement, depending on the context.

Sure, can you indicate which contexts you would like?

MISRA C:2004, 19.10

Ok.

MISRA C++:2008, 18-0-1 - The C library shall not be used.

Can you explain the impact of this change? I think I'm ok with it, but I'm not sure I understand exactly what would happen.

For this change, only when using C++, we're including the c++ version of the stdlib headers (so for example cstdarg instead of stdarg.h). The impact is compiler dependent, but most C++ compilers simply wrap the C versions so this should be negligible.

MISRA C:2004, 16.9 - A function identifier shall only be used with either a preceding &, or with a parenthesized parameter list, which may be empty.

Ok.

Unmodified pointers should be const (MISRA C:2004, 16.7 )

  1. I believe you are mis-applying the rule. There is a common signature to these functions, and buffer is generally modified.
  2. You seem to have two patches with this title, one saying "revert".

Correct, I came to same conclusion and reverted the commit.

MISRA C:2012, 20.1 - #include directives should only be preceded by preprocessor directives or comments

Ok.

Removed redundant cast

Ok.

Merge collapsible if statements (not strictly MISRA)

Don't have a strong opinion here; I probably separated for readability and consistency with other pieces of code earlier or below. Can you explain why you believe this is useful/important?

Mostly readability. Subsequent if statements imply more complexity than is actually present.

Rule 13.3 increment/decrement with other side effects

Generally ok, but see specific comment

I've changed the target to develop (still getting used to the github UI :) ).

@eyalroz
Copy link
Owner

eyalroz commented Jan 5, 2022

So, I'm going to go ahead and cherry-pick some of this PR. The rest will need a bit of updating for other changes.

@sanderh255 sanderh255 closed this Jan 5, 2022
@JakeSays
Copy link

JakeSays commented Jan 7, 2022

I'm little confused here. Couldn't MISRA compliance be met by using stdint.h types instead of a hack like printf_int_t?

@eyalroz
Copy link
Owner

eyalroz commented Jan 8, 2022

@JakeSays : Not unless I decided to force people to use non-native integer types (e.g. by choosing int32_t always,. or int64_t always).

@JakeSays
Copy link

JakeSays commented Jan 8, 2022

@eyalroz I'm not sure I follow. isn't stdint.h a standard? Personally I'd rather be forced to use int32_t instead of printf_int_t.

@eyalroz
Copy link
Owner

eyalroz commented Jan 8, 2022

Personally I'd rather be forced to use int32_t instead of printf_int_t.

  1. You won't see it anyway; the functions' interface remains the same as that of the standard. So why do you mind?

  2. Some people have 16-bit native-int platforms. Although... it's not like libprintf is ultra-fast to the degree that this makes a difference.

@JakeSays
Copy link

JakeSays commented Jan 8, 2022

  1. What? Why wouldn't I see it? It's in the header and the source.
  2. "MISRA C:2004, 6.3 - typedefs that indicate size and signedness should be used in place of the basic types" - wouldn't this require int32_t over int? Unless you want MISRA compliance to be optional.

My concern is this: One of the major attractions of libprintf is it's simplicity. The code is simple and easy to understand, and the header is a dream to read. It seems like many of these PR's are taking it in a different direction and it'll end up in #ifdef/#define hell.

@eyalroz
Copy link
Owner

eyalroz commented Jan 8, 2022

  1. What? Why wouldn't I see it? It's in the header and the source.

In this PR it is, but I don't think I would let it into the header. The fctprintf variants will return an int just like their standard library friends.

I still haven't seen an alternative PR. What I have done and committed to the code is drastically reduce the use of non-typedef'ed types in printf.c, using printf_size_t for widths, precision values etc.

kuba2k2 pushed a commit to libretiny-eu/library-printf that referenced this pull request Feb 25, 2023
* Fixes eyalroz#79.
* Fixed a few more (GCC) warnings.
* Separated the warning-triggering cases into test cases of their own.
* Not using `signed size_t` - that's apparently not in the standard and not widely supported.
* Added a CMake option for whether or not to test the warning-triggering cases.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants