mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[string] add compile-time check for printf style arg consistency (#8277)
This commit adds `OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK` macro in `toolchain.h`. It specifies that a function or method takes `printf` style args. It asks the compiler to check the args for consistency with the passed-in format string. The commit uses the new macro in `String::Append()` and its uses are updated to ensure consistency between format string and the args.
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (252)
|
||||
#define OPENTHREAD_API_VERSION (253)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -110,6 +110,24 @@ extern "C" {
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK
|
||||
*
|
||||
* This macro specifies that a function or method takes `printf` style arguments and should be type-checked against
|
||||
* a format string.
|
||||
*
|
||||
* This macro must be added after the function/method declaration. For example:
|
||||
*
|
||||
* `void MyPrintf(void *aObject, const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);`
|
||||
*
|
||||
* The two argument index values indicate format string and first argument to check against it. They start at index 1
|
||||
* for the first parameter in a function and at index 2 for the first parameter in a method.
|
||||
*
|
||||
* @param[in] aFmtIndex The argument index of the format string.
|
||||
* @param[in] aStartIndex The argument index of the first argument to check against the format string.
|
||||
*
|
||||
*/
|
||||
|
||||
// =========== TOOLCHAIN SELECTION : START ===========
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) || defined(__TI_ARM__)
|
||||
@@ -122,6 +140,9 @@ extern "C" {
|
||||
#define OT_TOOL_PACKED_END __attribute__((packed))
|
||||
#define OT_TOOL_WEAK __attribute__((weak))
|
||||
|
||||
#define OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(aFmtIndex, aStartIndex) \
|
||||
__attribute__((format(printf, aFmtIndex, aStartIndex)))
|
||||
|
||||
#elif defined(__ICCARM__) || defined(__ICC8051__)
|
||||
|
||||
// http://supp.iar.com/FilesPublic/UPDINFO/004916/arm/doc/EWARM_DevelopmentGuide.ENU.pdf
|
||||
@@ -133,6 +154,8 @@ extern "C" {
|
||||
#define OT_TOOL_PACKED_END
|
||||
#define OT_TOOL_WEAK __weak
|
||||
|
||||
#define OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(aFmtIndex, aStartIndex)
|
||||
|
||||
#elif defined(__SDCC)
|
||||
|
||||
// Structures are packed by default in sdcc, as it primarily targets 8-bit MCUs.
|
||||
@@ -142,6 +165,8 @@ extern "C" {
|
||||
#define OT_TOOL_PACKED_END
|
||||
#define OT_TOOL_WEAK
|
||||
|
||||
#define OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(aFmtIndex, aStartIndex)
|
||||
|
||||
#else
|
||||
|
||||
#error "Error: No valid Toolchain specified"
|
||||
@@ -153,6 +178,8 @@ extern "C" {
|
||||
#define OT_TOOL_PACKED_END
|
||||
#define OT_TOOL_WEAK
|
||||
|
||||
#define OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(aFmtIndex, aStartIndex)
|
||||
|
||||
#endif
|
||||
|
||||
// =========== TOOLCHAIN SELECTION : END ===========
|
||||
|
||||
@@ -187,6 +187,19 @@ template <typename IntType> inline IntType DivideAndRoundToClosest(IntType aDivi
|
||||
return (aDividend + (aDivisor / 2)) / aDivisor;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function casts a given `uint32_t` to `unsigned long`.
|
||||
*
|
||||
* @param[in] aUint32 A `uint32_t` value.
|
||||
*
|
||||
* @returns The @p aUint32 value as `unsigned long`.
|
||||
*
|
||||
*/
|
||||
inline unsigned long ToUlong(uint32_t aUint32)
|
||||
{
|
||||
return static_cast<unsigned long>(aUint32);
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // NUM_UTILS_HPP_
|
||||
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
* @returns The string writer.
|
||||
*
|
||||
*/
|
||||
StringWriter &Append(const char *aFormat, ...);
|
||||
StringWriter &Append(const char *aFormat, ...) OT_TOOL_PRINTF_STYLE_FORMAT_ARG_CHECK(2, 3);
|
||||
|
||||
/**
|
||||
* This method appends `printf()` style formatted data to the buffer.
|
||||
|
||||
@@ -98,7 +98,7 @@ void Uptime::HandleTimer(void)
|
||||
mTimer.FireAt(mTimer.GetFireTime() + kTimerInterval);
|
||||
}
|
||||
|
||||
static uint32_t DivideAndGetRemainder(uint32_t &aDividend, uint32_t aDivisor)
|
||||
static uint16_t DivideAndGetRemainder(uint32_t &aDividend, uint32_t aDivisor)
|
||||
{
|
||||
// Returns the quotient of division `aDividend / aDivisor` and updates
|
||||
// `aDividend` to returns the remainder
|
||||
@@ -107,20 +107,20 @@ static uint32_t DivideAndGetRemainder(uint32_t &aDividend, uint32_t aDivisor)
|
||||
|
||||
aDividend -= quotient * aDivisor;
|
||||
|
||||
return quotient;
|
||||
return static_cast<uint16_t>(quotient);
|
||||
}
|
||||
|
||||
void Uptime::UptimeToString(uint64_t aUptime, StringWriter &aWriter)
|
||||
{
|
||||
uint64_t days = aUptime / Time::kOneDayInMsec;
|
||||
uint32_t remainder;
|
||||
uint32_t hours;
|
||||
uint32_t minutes;
|
||||
uint32_t seconds;
|
||||
uint16_t hours;
|
||||
uint16_t minutes;
|
||||
uint16_t seconds;
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
aWriter.Append("%lud.", days);
|
||||
aWriter.Append("%lud.", static_cast<unsigned long>(days));
|
||||
aUptime -= days * Time::kOneDayInMsec;
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ void Uptime::UptimeToString(uint64_t aUptime, StringWriter &aWriter)
|
||||
minutes = DivideAndGetRemainder(remainder, Time::kOneMinuteInMsec);
|
||||
seconds = DivideAndGetRemainder(remainder, Time::kOneSecondInMsec);
|
||||
|
||||
aWriter.Append("%02u:%02u:%02u.%03u", hours, minutes, seconds, remainder);
|
||||
aWriter.Append("%02u:%02u:%02u.%03u", hours, minutes, seconds, static_cast<uint16_t>(remainder));
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
@@ -174,11 +174,12 @@ JoinerDiscerner::InfoString JoinerDiscerner::ToString(void) const
|
||||
}
|
||||
else if (mLength <= sizeof(uint32_t) * CHAR_BIT)
|
||||
{
|
||||
string.Append("0x%08x", static_cast<uint32_t>(mValue));
|
||||
string.Append("0x%08lx", ToUlong(static_cast<uint32_t>(mValue)));
|
||||
}
|
||||
else
|
||||
{
|
||||
string.Append("0x%x-%08x", static_cast<uint32_t>(mValue >> 32), static_cast<uint32_t>(mValue));
|
||||
string.Append("0x%lx-%08lx", ToUlong(static_cast<uint32_t>(mValue >> 32)),
|
||||
ToUlong(static_cast<uint32_t>(mValue)));
|
||||
}
|
||||
|
||||
string.Append("/len:%d", mLength);
|
||||
|
||||
@@ -94,7 +94,8 @@ Header::InfoString Header::ToString(void) const
|
||||
break;
|
||||
}
|
||||
|
||||
string.Append(" panid:%04x num:%lu src:%s", GetPanId(), GetPacketNumber(), GetSource().ToString().AsCString());
|
||||
string.Append(" panid:%04x num:%lu src:%s", GetPanId(), ToUlong(GetPacketNumber()),
|
||||
GetSource().ToString().AsCString());
|
||||
|
||||
if ((type == kTypeUnicast) || (type == kTypeAck))
|
||||
{
|
||||
|
||||
@@ -456,7 +456,7 @@ Publisher::Entry::InfoString Publisher::Entry::ToString(bool aIncludeState) cons
|
||||
break;
|
||||
}
|
||||
|
||||
string.Append(prefixEntry.mPrefix.ToString().AsCString());
|
||||
string.Append("%s", prefixEntry.mPrefix.ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user