Skip to content

Commit 280acb1

Browse files
ukleinekjic23
authored andcommitted
iio: adc: ad4130: Fix comparison of channel setups
Checking the binary representation of two structs (of the same type) for equality doesn't have the same semantic as comparing all members for equality. The former might find a difference where the latter doesn't in the presence of padding or when ambiguous types like float or bool are involved. (Floats typically have different representations for single values, like -0.0 vs +0.0, or 0.5 * 2² vs 0.25 * 2³. The type bool has at least 8 bits and the raw values 1 and 2 (probably) both evaluate to true, but memcmp finds a difference.) When searching for a channel that already has the configuration we need, the comparison by member is the one that is needed. Convert the comparison accordingly to compare the members one after another. Also add a static_assert guard to (somewhat) ensure that when struct ad4130_setup_info is expanded, the comparison is adapted, too. This issue is somewhat theoretic, but using memcmp() on a struct is a bad pattern that is worth fixing. Fixes: 6209406 ("iio: adc: ad4130: add AD4130 driver") Signed-off-by: Uwe Kleine-König <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jonathan Cameron <[email protected]>
1 parent fb3a081 commit 280acb1

File tree

1 file changed

+39
-2
lines changed

1 file changed

+39
-2
lines changed

drivers/iio/adc/ad4130.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ enum ad4130_pin_function {
224224
AD4130_PIN_FN_VBIAS = BIT(3),
225225
};
226226

227+
/*
228+
* If you make adaptations in this struct, you most likely also have to adapt
229+
* ad4130_setup_info_eq(), too.
230+
*/
227231
struct ad4130_setup_info {
228232
unsigned int iout0_val;
229233
unsigned int iout1_val;
@@ -592,6 +596,40 @@ static irqreturn_t ad4130_irq_handler(int irq, void *private)
592596
return IRQ_HANDLED;
593597
}
594598

599+
static bool ad4130_setup_info_eq(struct ad4130_setup_info *a,
600+
struct ad4130_setup_info *b)
601+
{
602+
/*
603+
* This is just to make sure that the comparison is adapted after
604+
* struct ad4130_setup_info was changed.
605+
*/
606+
static_assert(sizeof(*a) ==
607+
sizeof(struct {
608+
unsigned int iout0_val;
609+
unsigned int iout1_val;
610+
unsigned int burnout;
611+
unsigned int pga;
612+
unsigned int fs;
613+
u32 ref_sel;
614+
enum ad4130_filter_mode filter_mode;
615+
bool ref_bufp;
616+
bool ref_bufm;
617+
}));
618+
619+
if (a->iout0_val != b->iout0_val ||
620+
a->iout1_val != b->iout1_val ||
621+
a->burnout != b->burnout ||
622+
a->pga != b->pga ||
623+
a->fs != b->fs ||
624+
a->ref_sel != b->ref_sel ||
625+
a->filter_mode != b->filter_mode ||
626+
a->ref_bufp != b->ref_bufp ||
627+
a->ref_bufm != b->ref_bufm)
628+
return false;
629+
630+
return true;
631+
}
632+
595633
static int ad4130_find_slot(struct ad4130_state *st,
596634
struct ad4130_setup_info *target_setup_info,
597635
unsigned int *slot, bool *overwrite)
@@ -605,8 +643,7 @@ static int ad4130_find_slot(struct ad4130_state *st,
605643
struct ad4130_slot_info *slot_info = &st->slots_info[i];
606644

607645
/* Immediately accept a matching setup info. */
608-
if (!memcmp(target_setup_info, &slot_info->setup,
609-
sizeof(*target_setup_info))) {
646+
if (ad4130_setup_info_eq(target_setup_info, &slot_info->setup)) {
610647
*slot = i;
611648
return 0;
612649
}

0 commit comments

Comments
 (0)