Skip to content

Conversation

@Naveed8951
Copy link

__builtin_ctz(0) is undefined behavior under GCC/Clang and may lead to
miscompilation if the compiler assumes the argument is non-zero.

Replace the macro implementation with a static inline helper that
explicitly handles the zero case before calling the builtin. Apply the
same defined behavior to the MSVC _BitScanForward() path for consistency.

unsigned long bit;
unsigned long index;

/*
Copy link
Member

Choose a reason for hiding this comment

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

You can remove the test for the result being zero, but please don't remove the comment, as it still applies, as far as I know.

Copy link
Member

Choose a reason for hiding this comment

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

And if the parameter is changed to u_int, and the case is removed, as per https://github.com/the-tcpdump-group/libpcap/pull/1608/files#r2678473653, the comment no longer applies.

optimize.c Outdated
struct block *b;

for (i = 0; i < opt_state->n_blocks; ++i)
for ( i = 0; i < opt_state->n_blocks; ++i)
Copy link
Member

Choose a reason for hiding this comment

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

Please don't add an extra space there.

*
* If handed zero, the results are platform- and compiler-dependent.
* Keep it out of the light, don't give it any water, don't feed it
* after midnight, and don't pass zero to it.
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

@guyharris
Copy link
Member

As noted in the comment before all the declarations of lowest_set_bit(), it MUST not be called with a zero value and as seen in the one and only place lowest_set_bit() is called, it isn't called with a zero value (the loop it's called in loops as long as x is non-zero, and x is the argument to lowest_set_bit()), so it's not as if there's currently a bug caused by this.

However, any compiler worth its salt will figure out that it's being called with a guaranteed-not-to-be-zero value and optimize the test away, so this probably will cause the same code to be generated on any such compiler, so we might as well change it in case any other code ends up using it.

@Naveed8951
Copy link
Author

I’ve pushed updates addressing all review feedback: the original comment is restored, the redundant zero check is removed, and the formatting issue is fixed.

Please let me know if there’s anything further to adjust.

optimize.c Outdated
{
if (mask == 0)
return 0;
return (u_int)__builtin_ctz((unsigned int)mask);
Copy link
Member

Choose a reason for hiding this comment

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

mask is an u_int . Why do you cast it to unsigned int?

@Naveed8951
Copy link
Author

Good catch the cast is unnecessary here. mask is already an unsigned integer type and the zero case is handled before the builtin is called I’ll drop the cast to keep the code clearer and consistent

optimize.c Outdated
#endif

static __forceinline u_int
lowest_set_bit(int mask)
Copy link
Member

Choose a reason for hiding this comment

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

For consistency, make the argument a u_int, just as it is for the other version. The argument passed to it in the only call we currently make to it is a bpf_u_int32, which is the exact same type on all the platforms on which we run.

That would also mean that we don't need to cast mask to unsigned long - it will get promoted to unsigned long and no sign-extension will be done.

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 changed lowest_set_bit() to take a u_int argument for consistency with the other implementation and the current call site, and removed the unnecessary cast.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants