Skip to content

Commit 05a5d87

Browse files
ukleinekjic23
authored andcommitted
iio: adc: ad7124: Fix comparison of channel configs
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 ad7124_channel_config::config_props 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: 7b8d045 ("iio: adc: ad7124: allow more than 8 channels") 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 280acb1 commit 05a5d87

File tree

1 file changed

+31
-4
lines changed

1 file changed

+31
-4
lines changed

drivers/iio/adc/ad7124.c

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,11 @@ struct ad7124_chip_info {
151151
struct ad7124_channel_config {
152152
bool live;
153153
unsigned int cfg_slot;
154-
/* Following fields are used to compare equality. */
154+
/*
155+
* Following fields are used to compare for equality. If you
156+
* make adaptations in it, you most likely also have to adapt
157+
* ad7124_find_similar_live_cfg(), too.
158+
*/
155159
struct_group(config_props,
156160
enum ad7124_ref_sel refsel;
157161
bool bipolar;
@@ -338,15 +342,38 @@ static struct ad7124_channel_config *ad7124_find_similar_live_cfg(struct ad7124_
338342
struct ad7124_channel_config *cfg)
339343
{
340344
struct ad7124_channel_config *cfg_aux;
341-
ptrdiff_t cmp_size;
342345
int i;
343346

344-
cmp_size = sizeof_field(struct ad7124_channel_config, config_props);
347+
/*
348+
* This is just to make sure that the comparison is adapted after
349+
* struct ad7124_channel_config was changed.
350+
*/
351+
static_assert(sizeof_field(struct ad7124_channel_config, config_props) ==
352+
sizeof(struct {
353+
enum ad7124_ref_sel refsel;
354+
bool bipolar;
355+
bool buf_positive;
356+
bool buf_negative;
357+
unsigned int vref_mv;
358+
unsigned int pga_bits;
359+
unsigned int odr;
360+
unsigned int odr_sel_bits;
361+
unsigned int filter_type;
362+
}));
363+
345364
for (i = 0; i < st->num_channels; i++) {
346365
cfg_aux = &st->channels[i].cfg;
347366

348367
if (cfg_aux->live &&
349-
!memcmp(&cfg->config_props, &cfg_aux->config_props, cmp_size))
368+
cfg->refsel == cfg_aux->refsel &&
369+
cfg->bipolar == cfg_aux->bipolar &&
370+
cfg->buf_positive == cfg_aux->buf_positive &&
371+
cfg->buf_negative == cfg_aux->buf_negative &&
372+
cfg->vref_mv == cfg_aux->vref_mv &&
373+
cfg->pga_bits == cfg_aux->pga_bits &&
374+
cfg->odr == cfg_aux->odr &&
375+
cfg->odr_sel_bits == cfg_aux->odr_sel_bits &&
376+
cfg->filter_type == cfg_aux->filter_type)
350377
return cfg_aux;
351378
}
352379

0 commit comments

Comments
 (0)