Powered by Linux
Re: Adding PCI hotplug safe checking to smatch — Semantic Matching Tool

Re: Adding PCI hotplug safe checking to smatch

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

 



The infinite loop check seems to work pretty well.  I've attached the
patches and the results from an allmodconfig on linux-next.

If we have code like:

	if (readl() & FOO) {
		/* we can reach here if readl() succeeds or it fails */
	} else {
		/* we can only reach here if readl() succeeds.
	}

The test records if we rely on readl() to reach the start of a loop.
The it records if we rely on readl() to exit from the loop.

If we didn't need readl() to reach the start of the loop, but we need it
to exit the loop then print a warning.

If we hit a return statement then don't print any more warnings until
we have exited from all the loops.

The one false positive that I saw was code like this:

	while (readl() & BAR) {
		frob();
		if (x)
			goto end;
	}
	<-- can only reach here if readl() succeeds.

	frob();
end:
	wow_much_frob();

It's not a forever loop because of the goto.

regards,
dan carpenter

>From a05392caf5ea7444aa1d43b6d6a140a08fad4079 Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
Date: Tue, 28 Jan 2014 03:13:47 +0300
Subject: [PATCH 1/2] flow: add a STMT_HOOK_AFTER hook

It's like the other STMT_HOOK but it is called after a statement has been
processed instead of before.

Signed-off-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
---
 smatch.h       | 1 +
 smatch_flow.c  | 1 +
 smatch_hooks.c | 3 +++
 3 files changed, 5 insertions(+)

diff --git a/smatch.h b/smatch.h
index 717612ac7cb3..a4e88b217dba 100644
--- a/smatch.h
+++ b/smatch.h
@@ -81,6 +81,7 @@ DECLARE_PTR_LIST(tracker_list, struct tracker);
 enum hook_type {
 	EXPR_HOOK,
 	STMT_HOOK,
+	STMT_HOOK_AFTER,
 	SYM_HOOK,
 	STRING_HOOK,
 	DECLARATION_HOOK,
diff --git a/smatch_flow.c b/smatch_flow.c
index 3705a9415c55..bfe06ad58b5b 100644
--- a/smatch_flow.c
+++ b/smatch_flow.c
@@ -782,6 +782,7 @@ void __split_stmt(struct statement *stmt)
 		__split_expr(stmt->range_high);
 		break;
 	}
+	__pass_to_client(stmt, STMT_HOOK_AFTER);
 out:
 	__process_post_op_stack();
 }
diff --git a/smatch_hooks.c b/smatch_hooks.c
index c471d75ee914..57e39826a1e9 100644
--- a/smatch_hooks.c
+++ b/smatch_hooks.c
@@ -48,6 +48,9 @@ void add_hook(void *func, enum hook_type type)
 	case STMT_HOOK:
 		container->data_type = STMT_PTR;
 		break;
+	case STMT_HOOK_AFTER:
+		container->data_type = STMT_PTR;
+		break;
 	case SYM_HOOK:
 		container->data_type = EXPR_PTR;
 		break;
-- 
1.8.0.rc0.18.gf84667d.dirty

>From 867696d037e997ffa0b07ed84cb825e0479dcf7e Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
Date: Tue, 28 Jan 2014 03:19:36 +0300
Subject: [PATCH 2/2] *new* readl_infinite_loops: check for hotplug bugs which
 could cause hangs

I've a device is pulled then readl() returns ((uint)-1).  A lot of code
doesn't check for that and does:

	while (readl() & 0x80)
		;

If the device has been pulled then that will loop forever.  Thanks to
Joe Lawrence, for suggesting this.

Reported-by: Joe Lawrence <joe.lawrence@xxxxxxxxxxx>
Signed-off-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
---
 check_list.h                 |   1 +
 check_readl_infinite_loops.c | 157 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)
 create mode 100644 check_readl_infinite_loops.c

diff --git a/check_list.h b/check_list.h
index 5983330ada26..fd4d5b4482a1 100644
--- a/check_list.h
+++ b/check_list.h
@@ -96,6 +96,7 @@ CK(check_missing_break)
 CK(check_array_condition)
 CK(check_struct_type)
 CK(check_cast_assign)
+CK(check_readl_infinite_loops)
 
 /* <- your test goes here */
 /* CK(register_template) */
diff --git a/check_readl_infinite_loops.c b/check_readl_infinite_loops.c
new file mode 100644
index 000000000000..7915330caad0
--- /dev/null
+++ b/check_readl_infinite_loops.c
@@ -0,0 +1,157 @@
+/*
+ * smatch/check_readl_hotplug.c
+ *
+ * Copyright (C) 2014 Oracle.
+ *
+ * Licensed under the Open Software License version 1.1
+ *
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+
+static int my_id;
+
+STATE(readl);
+STATE(readl_ff);
+STATE(readl_00);
+
+DECLARE_PTR_LIST(state_stack, struct smatch_state);
+struct state_stack *state_at_start;
+
+static int readl_has_been_called;
+static int returned;
+
+static int is_readl_call(struct expression *expr)
+{
+	struct symbol *sym;
+
+	expr = strip_expr(expr);
+	if (expr->type != EXPR_CALL)
+		return 0;
+	if (expr->fn->type != EXPR_SYMBOL)
+		return 0;
+	sym = expr->fn->symbol;
+	if (!sym || !sym->ident)
+		return 0;
+	if (strcmp(sym->ident->name, "readl") != 0)
+		return 0;
+	return 1;
+}
+
+static int is_readl(struct expression *expr)
+{
+	if (is_readl_call(expr))
+		return 1;
+	if (get_state_expr(my_id, expr) == &readl)
+		return 1;
+	return 0;
+}
+
+static void match_assign(struct expression *expr)
+{
+	if (is_readl(expr->right))
+		set_state_expr(my_id, expr->left, &readl);
+	else if (get_state_expr(my_id, expr->left))
+		set_state_expr(my_id, expr->left, &undefined);
+}
+
+static int condition_depends_on_readl(struct expression *expr)
+{
+	if (expr->type == EXPR_BINOP) {
+		if (condition_depends_on_readl(expr->left))
+			return 1;
+		if (condition_depends_on_readl(expr->right))
+			return 1;
+		return 0;
+	}
+	if (is_readl(expr))
+		return 1;
+	return 0;
+}
+
+static void check_condition(struct expression *expr)
+{
+	if (expr->op != '&')
+		return;
+	if (!condition_depends_on_readl(expr))
+		return;
+	readl_has_been_called = 1;
+	set_true_false_states(my_id, "depends on", NULL, &readl_ff, &readl_00);
+}
+
+static void match_return(struct expression *expr)
+{
+
+	if (__inline_fn)
+		return;
+	returned = 1;
+#if 0
+	struct smatch_state *tmp;
+
+	if (!readl_has_been_called)
+		return;
+
+	FOR_EACH_PTR(state_at_start, tmp) {
+		REPLACE_CURRENT_PTR(tmp, NULL);
+	}
+#endif
+}
+
+static void push_state_at_start(struct smatch_state *state)
+{
+	add_ptr_list(&state_at_start, state);
+}
+
+static struct smatch_state *pop_state_at_start(void)
+{
+	struct smatch_state *state;
+
+	state = last_ptr_list((struct ptr_list *)state_at_start);
+	delete_ptr_list_last((struct ptr_list **)&state_at_start);
+	return state;
+}
+
+static void before_loop(struct statement *stmt)
+{
+	struct smatch_state *state;
+
+	if (!stmt || stmt->type != STMT_ITERATOR)
+		return;
+	if (ptr_list_empty(state_at_start))
+		returned = 0;
+	state = get_state(my_id, "depends on", NULL);
+	push_state_at_start(state);
+}
+
+static void after_loop(struct statement *stmt)
+{
+	struct smatch_state *old_state;
+
+	if (!stmt || stmt->type != STMT_ITERATOR)
+		return;
+	old_state = pop_state_at_start();
+	if (old_state == &readl_00)
+		return;
+	if (returned)
+		return;
+	if (get_state(my_id, "depends on", NULL) != &readl_00)
+		return;
+	sm_msg("warn: this loop depends on readl() succeeding");
+}
+
+void check_readl_infinite_loops(int id)
+{
+	if (option_project != PROJ_KERNEL)
+		return;
+
+	my_id = id;
+
+	add_hook(match_assign, ASSIGNMENT_HOOK);
+	add_hook(check_condition, CONDITION_HOOK);
+
+	add_hook(&match_return, RETURN_HOOK);
+
+	add_hook(before_loop, STMT_HOOK);
+	add_hook(after_loop, STMT_HOOK_AFTER);
+}
-- 
1.8.0.rc0.18.gf84667d.dirty

drivers/iommu/amd_iommu.c:802 amd_iommu_int_thread() warn: this loop depends on readl() succeeding
drivers/iommu/dmar.c:1004 dmar_disable_qi() warn: this loop depends on readl() succeeding
drivers/iommu/dmar.c:1004 dmar_disable_qi() warn: this loop depends on readl() succeeding
drivers/iommu/dmar.c:1272 dmar_fault() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:975 iommu_flush_write_buffer() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:975 iommu_flush_write_buffer() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:1183 iommu_disable_protect_mem_regions() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:1183 iommu_disable_protect_mem_regions() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:1216 iommu_disable_translation() warn: this loop depends on readl() succeeding
drivers/iommu/intel-iommu.c:1216 iommu_disable_translation() warn: this loop depends on readl() succeeding
drivers/iommu/intel_irq_remapping.c:499 iommu_disable_irq_remapping() warn: this loop depends on readl() succeeding
drivers/iommu/intel_irq_remapping.c:499 iommu_disable_irq_remapping() warn: this loop depends on readl() succeeding
drivers/usb/gadget/mv_udc_core.c:196 process_ep_req() warn: this loop depends on readl() succeeding
drivers/usb/early/ehci-dbgp.c:1072 kgdbdbgp_reader_thread() warn: this loop depends on readl() succeeding
drivers/net/ethernet/intel/ixgb/ixgb_hw.c:777 ixgb_read_phy_reg() warn: this loop depends on readl() succeeding
drivers/net/ethernet/intel/ixgb/ixgb_hw.c:804 ixgb_read_phy_reg() warn: this loop depends on readl() succeeding
drivers/net/ethernet/intel/ixgb/ixgb_hw.c:873 ixgb_write_phy_reg() warn: this loop depends on readl() succeeding
drivers/net/ethernet/intel/ixgb/ixgb_hw.c:900 ixgb_write_phy_reg() warn: this loop depends on readl() succeeding
drivers/net/ethernet/natsemi/ns83820.c:1532 ns83820_do_reset() warn: this loop depends on readl() succeeding
drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c:219 dwmac_dma_flush_tx_fifo() warn: this loop depends on readl() succeeding
drivers/net/ethernet/amd/amd8111e.c:129 amd8111e_read_phy() warn: this loop depends on readl() succeeding
drivers/net/ethernet/amd/amd8111e.c:159 amd8111e_write_phy() warn: this loop depends on readl() succeeding
drivers/net/ethernet/amd/amd8111e.c:818 amd8111e_rx_poll() warn: this loop depends on readl() succeeding
drivers/net/ethernet/brocade/bna/bfa_ioc_ct.c:882 bfa_ioc_ct2_pll_init() warn: this loop depends on readl() succeeding
drivers/net/ethernet/brocade/bna/bfa_ioc.c:1176 bfa_ioc_hw_sem_init() warn: this loop depends on readl() succeeding
drivers/net/ethernet/sun/cassini.c:3508 cas_start_dma() warn: this loop depends on readl() succeeding
drivers/net/ethernet/sun/sunhme.c:650 set_happy_link_modes() warn: this loop depends on readl() succeeding
drivers/net/ethernet/adaptec/starfire.c:1541 netdev_poll() warn: this loop depends on readl() succeeding
drivers/dma/dw/core.c:207 dwc_chan_disable() warn: this loop depends on readl() succeeding
drivers/dma/dw/core.c:1176 dwc_free_chan_resources() warn: this loop depends on readl() succeeding
drivers/dma/dw/core.c:1471 dw_dma_off() warn: this loop depends on readl() succeeding
drivers/input/serio/altera_ps2.c:66 altera_ps2_open() warn: this loop depends on readl() succeeding
drivers/media/pci/ddbridge/ddbridge-core.c:1011 input_tasklet() warn: this loop depends on readl() succeeding
drivers/media/pci/ddbridge/ddbridge-core.c:1356 flashio() warn: this loop depends on readl() succeeding
drivers/media/pci/ddbridge/ddbridge-core.c:1376 flashio() warn: this loop depends on readl() succeeding
drivers/spi/spi-imx.c:421 mx31_reset() warn: this loop depends on readl() succeeding
drivers/video/neofb.c:485 neo2200_sync() warn: this loop depends on readl() succeeding
drivers/infiniband/hw/amso1100/c2_qp.c:737 c2_activity() warn: this loop depends on readl() succeeding
drivers/infiniband/hw/nes/nes_utils.c:403 nes_read16_eeprom() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:130 write_fifo_isac() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:47 readisac() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:64 writeisac() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:112 read_fifo_isac() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:80 readhscx() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:96 writehscx() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:147 read_fifo_hscx() warn: this loop depends on readl() succeeding
drivers/isdn/hisax/telespci.c:165 write_fifo_hscx() warn: this loop depends on readl() succeeding
drivers/scsi/3w-sas.c:1200 twl_interrupt() warn: this loop depends on readl() succeeding
drivers/scsi/3w-sas.c:1349 twl_reset_sequence() warn: this loop depends on readl() succeeding
drivers/scsi/dpt_i2o.c:2137 adpt_isr() warn: this loop depends on readl() succeeding
drivers/scsi/3w-9xxx.c:1516 twa_poll_status_gone() warn: this loop depends on readl() succeeding
drivers/scsi/bfa/bfa_ioc.c:718 bfa_iocpf_sm_fwcheck_entry() warn: this loop depends on readl() succeeding
drivers/scsi/megaraid.c:1233 issue_scb_block() warn: this loop depends on readl() succeeding
drivers/scsi/megaraid.c:1391 megaraid_isr_memmapped() warn: this loop depends on readl() succeeding
drivers/scsi/arcmsr/arcmsr_hba.c:2474 arcmsr_polling_hbc_ccbdone() warn: this loop depends on readl() succeeding
drivers/atm/idt77252.c:166 waitfor_idle() warn: this loop depends on readl() succeeding
drivers/atm/nicstarmac.c:171 read_eprom_byte() warn: this loop depends on readl() succeeding
drivers/atm/nicstarmac.c:170 read_eprom_byte() warn: this loop depends on readl() succeeding
drivers/atm/nicstarmac.c:215 nicstar_init_eprom() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:324 ns_read_sram() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:341 ns_write_sram() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:452 ns_init_card() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:1036 push_rxbufs() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:1438 ns_close() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:2812 ns_phy_put() warn: this loop depends on readl() succeeding
drivers/atm/nicstar.c:2827 ns_phy_get() warn: this loop depends on readl() succeeding
drivers/atm/he.c:204 he_readl_internal() warn: this loop depends on readl() succeeding
drivers/atm/he.c:188 he_writel_internal() warn: this loop depends on readl() succeeding
drivers/atm/he.c:2357 he_close() warn: this loop depends on readl() succeeding

[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux