Re: [PATCH 4/4] bad-shift: wait dead code elimination to warn about bad shifts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 06, 2020 at 09:30:03PM +0200, Luc Van Oostenryck wrote:
> Sparse complains when a shift amount is too big for the size
> of its operand or if it's negative.
> 
> However, it does this even for expressions that are never evaluated.
> It's especially annoying in the kernel for type generic macros,
> for example the ones in arch/*/include/asm/cmpxchg.h
> 
> So, remove all warnings done at expansion time and avoid any
> simplifications of such expressions. Same, at linearization
> and optimization time but in this case mark the instructions as
> 'tainted' to inhibit any further simplifications. Finally, at the
> end of the optimization phase, warn for the tainted instructions.
> 
> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@xxxxxxxxx>
> ---
>  expand.c                      | 18 -------------
>  linearize.c                   | 44 ++++++++++++++++++++++++++++++++
>  simplify.c                    | 20 ++++-----------
>  validation/expand/bad-shift.c |  8 +++---
>  validation/optim/shift-big.c  | 12 ++++++---
>  validation/shift-negative.c   |  4 +--
>  validation/shift-undef-long.c |  7 +++--
>  validation/shift-undef.c      | 48 +++++++++--------------------------
>  8 files changed, 78 insertions(+), 83 deletions(-)
> 
> diff --git a/expand.c b/expand.c
> index b07893318382..623b180025ad 100644
> --- a/expand.c
> +++ b/expand.c
> @@ -170,22 +170,6 @@ Float:
>  	expr->type = EXPR_FVALUE;
>  }
>  
> -static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count)
> -{
> -	if (count < 0) {
> -		if (!Wshift_count_negative)
> -			return;
> -		warning(expr->pos, "shift count is negative (%lld)", count);
> -		return;
> -	}
> -	if (ctype->type == SYM_NODE)
> -		ctype = ctype->ctype.base_type;
> -
> -	if (!Wshift_count_overflow)
> -		return;
> -	warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype));
> -}
> -
>  /* Return true if constant shift size is valid */
>  static bool check_shift_count(struct expression *expr, struct expression *right)
>  {
> @@ -194,8 +178,6 @@ static bool check_shift_count(struct expression *expr, struct expression *right)
>  
>  	if (count >= 0 && count < ctype->bit_size)
>  		return true;
> -	if (!conservative)
> -		warn_shift_count(expr, ctype, count);
>  	return false;
>  }
>  
> diff --git a/linearize.c b/linearize.c
> index 4927468183b0..5a8e74970d98 100644
> --- a/linearize.c
> +++ b/linearize.c
> @@ -2468,6 +2468,49 @@ static pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stm
>  	return VOID;
>  }
>  
> +static void check_tainted_insn(struct instruction *insn)
> +{
> +	unsigned long long uval;
> +	long long sval;
> +	pseudo_t src2;
> +
> +	switch (insn->opcode) {
> +	case OP_DIVU: case OP_DIVS:
> +	case OP_MODU: case OP_MODS:
> +		if (insn->src2 == value_pseudo(0))
> +			warning(insn->pos, "divide by zero");
> +		break;

Is this divide by zero a new check?  I get the shift, but is this new?

> +	case OP_SHL: case OP_LSR: case OP_ASR:
> +		src2 = insn->src2;
> +		if (src2->type != PSEUDO_VAL)
> +			break;
> +		uval = src2->value;
> +		if (uval < insn->size)
> +			break;
> +		sval = sign_extend(uval, insn->size);
> +		if (Wshift_count_negative && sval < 0)
> +			warning(insn->pos, "shift count is negative (%lld)", sval);
> +		else if (Wshift_count_overflow)
> +			warning(insn->pos, "shift too big (%llu) for type %s", uval, show_typename(insn->type));

Makes sense.

> +	}
> +}
> +
> +///
> +// issue warnings after all possible DCE
> +static void late_warnings(struct entrypoint *ep)
> +{
> +	struct basic_block *bb;
> +	FOR_EACH_PTR(ep->bbs, bb) {
> +		struct instruction *insn;
> +		FOR_EACH_PTR(bb->insns, insn) {
> +			if (!insn->bb)
> +				continue;
> +			if (insn->tainted)
> +				check_tainted_insn(insn);
> +		} END_FOR_EACH_PTR(insn);
> +	} END_FOR_EACH_PTR(bb);
> +}
> +
>  static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_type)
>  {
>  	struct statement *stmt = base_type->stmt;
> @@ -2514,6 +2557,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t
>  	add_one_insn(ep, ret);
>  
>  	optimize(ep);
> +	late_warnings(ep);
>  	return ep;
>  }
>  
> diff --git a/simplify.c b/simplify.c
> index 7850bcdc6069..f6b79685f439 100644
> --- a/simplify.c
> +++ b/simplify.c
> @@ -754,28 +754,18 @@ static long long check_shift_count(struct instruction *insn, unsigned long long
>  	unsigned int size = insn->size;
>  	long long sval = uval;
>  
> +	if (insn->tainted)
> +		return -1;
> +
>  	if (uval < size)
>  		return uval;
>  
> +	insn->tainted = 1;
>  	sval = sign_extend_safe(sval, size);
>  	sval = sign_extend_safe(sval, bits_in_int);
>  	if (sval < 0)
>  		insn->src2 = value_pseudo(sval);
> -	if (insn->tainted)
> -		return sval;
> -
> -	if (sval < 0 && Wshift_count_negative)
> -		warning(insn->pos, "shift count is negative (%lld)", sval);
> -	if (sval > 0 && Wshift_count_overflow) {
> -		struct symbol *ctype = insn->type;
> -		const char *tname;
> -		if (ctype->type == SYM_NODE)
> -			ctype = ctype->ctype.base_type;
> -		tname = show_typename(ctype);
> -		warning(insn->pos, "shift too big (%llu) for type %s", sval, tname);
> -	}
> -	insn->tainted = 1;
> -	return sval;
> +	return -1;
>  }
>  
>  static int simplify_shift(struct instruction *insn, pseudo_t pseudo, long long value)
> diff --git a/validation/expand/bad-shift.c b/validation/expand/bad-shift.c
> index 22c4341f1680..b68866c2b048 100644
> --- a/validation/expand/bad-shift.c
> +++ b/validation/expand/bad-shift.c
> @@ -56,9 +56,9 @@ rneg:
>   * check-output-end
>   *
>   * check-error-start
> -expand/bad-shift.c:5:18: warning: shift too big (32) for type int
> -expand/bad-shift.c:10:18: warning: shift count is negative (-1)
> -expand/bad-shift.c:15:18: warning: shift too big (32) for type int
> -expand/bad-shift.c:20:18: warning: shift count is negative (-1)
> +expand/bad-shift.c:5:21: warning: shift too big (32) for type int
> +expand/bad-shift.c:10:21: warning: shift count is negative (-1)
> +expand/bad-shift.c:15:21: warning: shift too big (32) for type int
> +expand/bad-shift.c:20:21: warning: shift count is negative (-1)
>   * check-error-end
>   */
> diff --git a/validation/optim/shift-big.c b/validation/optim/shift-big.c
> index 84bcd2ce01a3..e7bf22fe36ff 100644
> --- a/validation/optim/shift-big.c
> +++ b/validation/optim/shift-big.c
> @@ -50,13 +50,15 @@ lsr31:
>  lsr32:
>  .L8:
>  	<entry-point>
> -	ret.32      $0
> +	lsr.32      %r14 <- %arg1, $32
> +	ret.32      %r14
>  
>  
>  lsr33:
>  .L10:
>  	<entry-point>
> -	ret.32      $0
> +	lsr.32      %r17 <- %arg1, $33
> +	ret.32      %r17
>  
>  
>  shl31:
> @@ -69,13 +71,15 @@ shl31:
>  shl32:
>  .L14:
>  	<entry-point>
> -	ret.32      $0
> +	shl.32      %r23 <- %arg1, $32
> +	ret.32      %r23
>  
>  
>  shl33:
>  .L16:
>  	<entry-point>
> -	ret.32      $0
> +	shl.32      %r26 <- %arg1, $33
> +	ret.32      %r26
>  
>  
>   * check-output-end
> diff --git a/validation/shift-negative.c b/validation/shift-negative.c
> index fff5cf123dd6..6df02b18468f 100644
> --- a/validation/shift-negative.c
> +++ b/validation/shift-negative.c
> @@ -9,8 +9,8 @@ unsigned int fo2(unsigned int a) { return a >> ((a & 0) ^ ~0); }
>   * check-command: sparse -Wno-decl $file
>   *
>   * check-error-start
> -shift-negative.c:1:45: warning: shift count is negative (-1)
> -shift-negative.c:2:45: warning: shift count is negative (-1)
> +shift-negative.c:1:48: warning: shift count is negative (-1)
> +shift-negative.c:2:48: warning: shift count is negative (-1)
>  shift-negative.c:4:59: warning: shift count is negative (-1)
>  shift-negative.c:5:59: warning: shift count is negative (-1)
>   * check-error-end
> diff --git a/validation/shift-undef-long.c b/validation/shift-undef-long.c
> index 326267436ec7..985fe4c4c595 100644
> --- a/validation/shift-undef-long.c
> +++ b/validation/shift-undef-long.c
> @@ -13,9 +13,8 @@ static unsigned very_big_shift(unsigned int a)
>   * check-command: sparse -m64 $file
>   *
>   * check-error-start
> -shift-undef-long.c:4:16: warning: shift too big (4294967295) for type unsigned int
> -shift-undef-long.c:5:16: warning: shift too big (4294967296) for type unsigned int
> -shift-undef-long.c:6:16: warning: shift too big (4294967296) for type unsigned int
> -shift-undef-long.c:7:16: warning: shift count is negative (-4294967296)
> +shift-undef-long.c:4:25: warning: shift count is negative (-1)
> +shift-undef-long.c:5:47: warning: shift too big (4294967296) for type unsigned int
> +shift-undef-long.c:7:20: warning: shift count is negative (-4294967296)
>   * check-error-end
>   */
> diff --git a/validation/shift-undef.c b/validation/shift-undef.c
> index 613c6b95b113..0c7541e9ffd9 100644
> --- a/validation/shift-undef.c
> +++ b/validation/shift-undef.c
> @@ -112,48 +112,24 @@ void hw_write(u32 val)
>   * check-command: sparse -Wno-decl $file
>   *
>   * check-error-start
> -shift-undef.c:3:15: warning: shift too big (100) for type int
> -shift-undef.c:4:15: warning: shift too big (101) for type unsigned int
> -shift-undef.c:5:15: warning: shift too big (102) for type unsigned int
> -shift-undef.c:6:15: warning: shift count is negative (-1)
> -shift-undef.c:7:15: warning: shift count is negative (-2)
> -shift-undef.c:8:15: warning: shift count is negative (-3)
> -shift-undef.c:9:25: warning: shift too big (103) for type int
> -shift-undef.c:10:25: warning: shift too big (104) for type unsigned int
> -shift-undef.c:11:25: warning: shift too big (105) for type unsigned int
> -shift-undef.c:12:25: warning: shift count is negative (-4)
> -shift-undef.c:13:25: warning: shift count is negative (-5)
> -shift-undef.c:14:25: warning: shift count is negative (-6)
> -shift-undef.c:15:30: warning: shift too big (106) for type int
> -shift-undef.c:16:30: warning: shift too big (107) for type unsigned int
> -shift-undef.c:17:30: warning: shift too big (108) for type unsigned int
> -shift-undef.c:18:30: warning: shift count is negative (-7)
> -shift-undef.c:19:30: warning: shift count is negative (-8)
> -shift-undef.c:20:30: warning: shift count is negative (-9)
> +shift-undef.c:3:18: warning: shift too big (100) for type int
> +shift-undef.c:4:18: warning: shift too big (101) for type unsigned int
> +shift-undef.c:5:18: warning: shift too big (102) for type unsigned int
> +shift-undef.c:6:19: warning: shift count is negative (-1)
> +shift-undef.c:7:19: warning: shift count is negative (-2)
> +shift-undef.c:8:19: warning: shift count is negative (-3)
>  shift-undef.c:21:29: warning: shift too big (109) for type int
>  shift-undef.c:22:29: warning: shift too big (110) for type unsigned int
>  shift-undef.c:23:29: warning: shift too big (111) for type unsigned int
>  shift-undef.c:24:29: warning: shift count is negative (-10)
>  shift-undef.c:25:29: warning: shift count is negative (-11)
>  shift-undef.c:26:29: warning: shift count is negative (-12)
> -shift-undef.c:32:11: warning: shift too big (100) for type int
> -shift-undef.c:33:11: warning: shift too big (101) for type unsigned int
> -shift-undef.c:34:11: warning: shift too big (102) for type unsigned int
> -shift-undef.c:35:11: warning: shift count is negative (-1)
> -shift-undef.c:36:11: warning: shift too big (4294967294) for type unsigned int
> -shift-undef.c:37:11: warning: shift too big (4294967293) for type unsigned int
> -shift-undef.c:38:25: warning: shift too big (103) for type int
> -shift-undef.c:39:25: warning: shift too big (104) for type unsigned int
> -shift-undef.c:40:25: warning: shift too big (105) for type unsigned int
> -shift-undef.c:41:25: warning: shift count is negative (-4)
> -shift-undef.c:42:25: warning: shift too big (4294967291) for type unsigned int
> -shift-undef.c:43:25: warning: shift too big (4294967290) for type unsigned int
> -shift-undef.c:44:30: warning: shift too big (106) for type int
> -shift-undef.c:45:30: warning: shift too big (107) for type unsigned int
> -shift-undef.c:46:30: warning: shift too big (108) for type unsigned int
> -shift-undef.c:47:30: warning: shift count is negative (-7)
> -shift-undef.c:48:30: warning: shift too big (4294967288) for type unsigned int
> -shift-undef.c:49:30: warning: shift too big (4294967287) for type unsigned int
> +shift-undef.c:32:15: warning: shift too big (100) for type int
> +shift-undef.c:33:15: warning: shift too big (101) for type unsigned int
> +shift-undef.c:34:15: warning: shift too big (102) for type unsigned int
> +shift-undef.c:35:16: warning: shift count is negative (-1)
> +shift-undef.c:36:16: warning: shift count is negative (-2)
> +shift-undef.c:37:16: warning: shift count is negative (-3)
>  shift-undef.c:50:26: warning: shift too big (109) for type int
>  shift-undef.c:51:26: warning: shift too big (110) for type unsigned int
>  shift-undef.c:52:26: warning: shift too big (111) for type unsigned int
> -- 
> 2.28.0
> 



[Index of Archives]     [Newbies FAQ]     [LKML]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Trinity Fuzzer Tool]

  Powered by Linux