Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions src/common/StatusArg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,19 +407,25 @@ Num::Num(ISC_STATUS s) noexcept :
Int64::Int64(SINT64 val) noexcept :
Str(text)
{
snprintf(text, sizeof(text), "%" SQUADFORMAT, val);
[[maybe_unused]] auto result = snprintf(text, sizeof(text), "%" SQUADFORMAT, val);
fb_assert(result >= 0 && result < sizeof(text));
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Adding asserts is good idea - but they should be complete. Look here:

From man:
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit, then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available. Thus, a return value of size or more means that the output was truncated.

I.e. sizeof(text) should also be taken into an account.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done. Please, see changes


Int64::Int64(FB_UINT64 val) noexcept :
Str(text)
{
snprintf(text, sizeof(text), "%" UQUADFORMAT, val);
[[maybe_unused]] auto result = snprintf(text, sizeof(text), "%" UQUADFORMAT, val);
fb_assert(result >= 0 && result < sizeof(text));
}

Quad::Quad(const ISC_QUAD* quad) noexcept :
Str(text)
{
snprintf(text, sizeof(text), "%x:%x", quad->gds_quad_high, quad->gds_quad_low);
[[maybe_unused]] auto result = snprintf(text, sizeof(text), "%x:%x",
static_cast<unsigned int>(quad->gds_quad_high),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Format is hexadecimal. What's wrong with signed integer?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

See page 332 of https://open-std.org/JTC1/SC22/WG14/www/docs/n3220.pdf

b,B,o,u,x,X The unsigned int argument is converted to unsigned binary (b or B), unsigned octal
(o), unsigned decimal (u), or unsigned hexadecimal notation (x or X)

Looks like it does not care about sign. Not sure what changes when you pass signed integer instead, probably nothing? Anyway, static_cast makes it more explicit

Copy link
Copy Markdown
Contributor

@aafemt aafemt Apr 2, 2026

Choose a reason for hiding this comment

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

Not sure what changes when you pass signed integer instead, probably nothing?

Exactly as written in your quote: for x specifier corresponding parameter is considered to be unsigned int. No explicit cast is needed as long as parameter's size matches. That's the way variadic functions work: they use reinterpret_cast inside.

Copy link
Copy Markdown

@craftmaster1231 craftmaster1231 Apr 2, 2026

Choose a reason for hiding this comment

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

Static analyzer was triggered just because of different types. I agree, in this case there are not any problems just because of differing types, but there is a reason to consider this cast as a good practice:

va_arg call with unsigned int argument while original type is int will be valid only if original int is non-negative.
If int is negative for some reason, we will face UB without this fix. With fix, value will just wrap around without UB.

page 289 for va_arg:
If type is not compatible with the type of the actual next argument (as promoted according to
the default argument promotions), the behavior is undefined, except for the following cases:

...

  • one type is compatible with a signed integer type, the other type is compatible with the
    corresponding unsigned integer type, and the value is representable in both types

...

quad->gds_quad_low
);
fb_assert(result >= 0 && result < sizeof(text));
}

Interpreted::Interpreted(const char* text) noexcept :
Expand Down