lkml.org 
[lkml]   [2013]   [Aug]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
Subjectdo_div() silently truncates "base" to 32bit
From
Hi,


I was debugging weird "zero divide" problem in CFQ code below


static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf,
struct blkg_policy_data *pd, int off)
{
struct cfq_group *cfqg = pd_to_cfqg(pd);
u64 samples = blkg_stat_read(&cfqg->stats.avg_queue_size_samples);
u64 v = 0;

if (samples) {
v = blkg_stat_read(&cfqg->stats.avg_queue_size_sum);
do_div(v, samples);
}
__blkg_prfill_u64(sf, pd, v);
return 0;
}


do_div() crashes says "zero divide". It is weird because just a few
lines above we check divider for zero.


The problem comes from include/asm-generic/div64.h file that
implements do_div() as macros:

# define do_div(n,base) ({ \
uint32_t __base = (base); \
uint32_t __rem; \
__rem = ((uint64_t)(n)) % __base; \
(n) = ((uint64_t)(n)) / __base; \
__rem; \
})


Do you see the problem?

The problem here is that "base" argument is truncated to 32bit, but in
the function above "sample" is 64bit variable. If sample's 32 low bits
are zero - we have a crash. in fact we have incorrect behavior any
time when high 32bits are non-zero.


My question is why the base is 32bit? Why not to use 64bit arguments?

Ideally if this macros is converted to a function so compiler will
warn us about unexpected truncation like this. But in this case it
will be hard to do as "n" parameter both input and output.


\
 
 \ /
  Last update: 2013-08-30 19:41    [W:0.403 / U:0.028 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site