Powered by Linux
Re: How does paired function checking implement in Smatch? — Semantic Matching Tool

Re: How does paired function checking implement in Smatch?

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

 



Btw, here is the diff between my code and the released code.  To be
honest, I don't look at these results or I would have noticed when
devm_add_action_or_reset() changed from a function to a macro.

I think the nla_nest_start() stuff is totally wrong but I don't
understand the rules with that.

regards,
dan carpenter
diff --git a/check_unwind.c b/check_unwind.c
index e2102ec76c14..4c3a743be8e6 100644
--- a/check_unwind.c
+++ b/check_unwind.c
@@ -35,6 +35,8 @@ STATE(unknown);
 
 static unsigned long fn_has_alloc;
 
+static void handle_ida_destroy(const char *fn, struct expression *expr, void *data);
+
 struct ref_func_info {
 	const char *name;
 	int type;
@@ -88,14 +90,173 @@ static struct ref_func_info func_table[] = {
 	{ "pci_request_irq", ALLOC,   1, "$", &int_zero, &int_zero },
 	{ "pci_free_irq",    RELEASE, 1, "$" },
 
+	{ "irq_of_parse_and_map", ALLOC, -1, "$", &int_one, &int_max},
+	{ "irq_create_of_mapping", ALLOC, -1, "$", &int_one, &int_max},
+	{ "irq_dispose_mapping", RELEASE, 0, "$"},
+
 	{ "register_netdev",   ALLOC,   0, "$", &int_zero, &int_zero },
 	{ "unregister_netdev", RELEASE, 0, "$" },
 
 	{ "misc_register",   ALLOC,   0, "$", &int_zero, &int_zero },
 	{ "misc_deregister", RELEASE, 0, "$" },
 
+	{ "__platform_driver_register", ALLOC,   0, "$", &int_zero, &int_zero },
+	{ "platform_driver_unregister", RELEASE, 0, "$" },
+
 	{ "ieee80211_alloc_hw", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
 	{ "ieee80211_free_hw",  RELEASE, 0, "$" },
+
+//	{ "init_timer_key", ALLOC,   0, "$" },
+	{ "del_timer_sync", RELEASE, 0, "$" },
+	{ "del_timer",      RELEASE, 0, "$" },
+	{ "cancel_delayed_work_sync", RELEASE, 0, "$" },
+
+	{ "dma_alloc_coherent", ALLOC,   -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_free_coherent",  RELEASE, 2, "$" },
+
+	{ "ida_alloc_max", ALLOC, -1, "$", &int_zero, &int_max },
+	{ "ida_alloc_range", ALLOC, -1, "$", &int_zero, &int_max },
+	{ "ida_free", RELEASE, 1, "$" },
+	{ "ida_destroy", RELEASE, 0, "$", NULL, NULL, &handle_ida_destroy },
+
+	{ "alloc_workqueue", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "destroy_workqueue", RELEASE, 0, "$" },
+
+	{ "__class_register", ALLOC, 0, "$", &int_zero, &int_zero },
+	{ "class_unregister", RELEASE, 0, "$" },
+
+	{ "clk_get", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "clk_put", RELEASE, 0, "$" },
+
+	{ "dev_pm_domain_attach", ALLOC, 0, "$", &int_zero, &int_zero },
+	{ "dev_pm_domain_attach_by_id", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dev_pm_domain_attach_by_name", ALLOC, 0, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dev_pm_domain_detach", RELEASE, 0, "$" },
+
+
+// To be honest, I don't understand the point of devfres_free().  I thought all
+// this stuff was supposed to be automatic.  (Probably everyone else doesn't
+// understand either which is we have all these bugs).
+//	{ "devres_alloc", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+//	{ "__devres_alloc_node", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+//	{ "devres_free", RELEASE, 0, "$" },
+
+//	{ "device_initialize",	ALLOC,   0, "$" },
+//	{ "dev_set_name",	ALLOC,   0, "$", &int_zero, &int_zero },
+	{ "device_register",	ALLOC,   0, "$", &int_zero, &int_zero },
+	{ "put_device",		RELEASE, 0, "$" },
+	{ "device_unregister",	RELEASE, 0, "$" },
+	{ "device_del",		RELEASE, 0, "$" },
+
+	// FIXME: dma returns are slightly different I think...
+	{ "dma_map_resource", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_unmap_resource", RELEASE, 1, "$" },
+
+	{ "dma_map_single_attrs", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_unmap_single_attrs", RELEASE, 1, "$" },
+	{ "usb_gadget_unmap_request", RELEASE, 1, "$->dma" },
+
+	{ "dma_request_slave_channel", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_request_chan", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_release_channel", RELEASE, 0, "$" },
+
+	{ "framebuffer_alloc", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "framebuffer_release", RELEASE, 0, "$" },
+
+	{ "get_device", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "put_device", RELEASE, 0, "$" },
+
+	{ "iio_channel_get", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "iio_channel_release", RELEASE, 0, "$" },
+
+	{ "input_allocate_device", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "input_free_device", RELEASE, 0, "$" },
+
+	{ "input_register_handle", ALLOC, 0, "$", &int_zero, &int_zero },
+	{ "input_unregister_handle", RELEASE, 0, "$" },
+
+	{ "mempool_alloc", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "mempool_free", RELEASE, 0, "$" },
+
+	{ "of_node_get", ALLOC, 0, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "of_get_next_available_child", RELEASE, 1, "$" },
+	{ "__of_find_node_by_full_path", RELEASE, 0, "$" },
+	{ "of_find_node_by_name", RELEASE, 0, "$" },
+	{ "of_node_put", RELEASE, 0, "$" },
+
+	{ "of_reserved_mem_device_init", ALLOC, 0, "$", &int_zero, &int_zero },
+	{ "of_reserved_mem_device_release", RELEASE, 0, "$" },
+
+	{ "pinctrl_register", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "pinctrl_unregister", RELEASE, 0, "$" },
+
+// sun6i_hwspinlock_probe() deliberately dasserts on success and asserts on failure
+//	{ "reset_control_assert", ALLOC, 0, "$", &int_zero, &int_zero },
+//	{ "reset_control_deassert", RELEASE, 0, "$" },
+
+	{ "scsi_host_alloc", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "scsi_host_put", RELEASE, 0, "$" },
+
+// Are these affected by pcim_enable_device()?
+//	{ "pci_alloc_irq_vectors", ALLOC, 0, "$",  &int_one, &int_max },
+//	{ "pci_free_irq_vectors", RELEASE, 0, "$" },
+//	{ "pci_dev_get", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+//	{ "pci_dev_put", RELEASE, 0, "$" },
+
+	// There are to many pci_enable_device warnings and it's not clear
+	// if we really want to disable the pci device anyway
+	// { "pci_enable_device", ALLOC, 0, "$", &int_zero, &int_zero },
+	// { "pci_disable_device", RELEASE, 0, "$" },
+
+	{ "spi_dev_get", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "spi_dev_put", RELEASE, 0, "$" },
+
+	{ "spi_message_alloc", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "spi_message_free", RELEASE, 0, "$" },
+
+	{ "spi_register_controller", ALLOC, 0, "$", &int_zero, &int_zero },
+	{ "spi_unregister_master", RELEASE, 0, "$" },
+	{ "spi_unregister_controller", RELEASE, 0, "$" },
+
+	{ "ovl_override_creds", ALLOC, -1, "$" },
+	{ "revert_creds", RELEASE, 0, "$" },
+
+	{ "dma_alloc_attrs", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dma_free_attrs", RELEASE, 2, "$" },
+
+	{ "alloc_pages", ALLOC,  -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "__get_free_pages", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "free_pages", RELEASE, 0, "$" },
+	{ "__free_pages", RELEASE, 0, "$" },
+	{ "put_page", RELEASE, 0, "$" },
+	{ "safe_put_page", RELEASE, 0, "$" },
+	{ "skb_fill_page_desc", IGNORE, 2, "$" },
+	{ "__skb_frag_set_page", IGNORE, 1, "$" },
+	{ "sg_set_page", IGNORE, 1, "$" },
+	{ "sg_assign_page", IGNORE, 1, "$" },
+	{ "ib_dma_map_page", IGNORE, 1, "$" },
+
+	{ "usb_get_intf", ALLOC,   0, "$"},
+	{ "usb_put_intf", RELEASE, 0, "$"},
+
+	{ "request_firmware", ALLOC, 0, "*$", &int_zero, &int_zero},
+	{ "release_firmware", RELEASE, 0, "$"},
+
+	{ "get_cred", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "put_cred", RELEASE, 0, "$" },
+
+	{ "damon_new_target", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "damon_add_target", RELEASE, 1, "$" },
+	{ "damon_add_target", ALLOC, 0, "$" },
+	{ "damon_sysfs_destroy_targets", RELEASE, 0, "$" },
+
+	{ "nla_nest_start_noflag", ALLOC, 0, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "nla_nest_start", ALLOC, 0, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "nla_nest_end", RELEASE, 0, "$" },
+	{ "nla_nest_cancel", RELEASE, 0, "$" },
+
+	{ "debugfs_lookup", ALLOC, -1, "$", &valid_ptr_min_sval, &valid_ptr_max_sval },
+	{ "dput", RELEASE, 0, "$" },
 };
 
 static struct smatch_state *unmatched_state(struct sm_state *sm)
@@ -275,6 +436,21 @@ static void return_param_ignore(struct expression *expr, const char *name, struc
 	update_ssa_sm(my_id, start_sm, &ignore);
 }
 
+static void handle_ida_destroy(const char *fn, struct expression *expr, void *data)
+{
+	struct sm_state *sm, *tmp;
+
+	FOR_EACH_SM_SAFE(__get_cur_stree(), sm) {
+		if (sm->owner != my_id)
+			continue;
+		FOR_EACH_PTR(sm->possible, tmp) {
+			if (strcmp(tmp->state->name, "ida_alloc_max") == 0 ||
+			    strcmp(tmp->state->name, "ida_alloc_range") == 0)
+				set_state(sm->owner, sm->name, sm->sym, &release);
+		} END_FOR_EACH_PTR(tmp);
+	} END_FOR_EACH_SM_SAFE(sm);
+}
+
 static void match_sm_assign(struct sm_state *sm, struct expression *mod_expr)
 {
 	char *left;
@@ -344,12 +520,14 @@ static void check_balance(const char *name, struct symbol *sym)
 
 		if (is_impossible_path())
 			goto swap_stree;
-		if (db_incomplete())
-			goto swap_stree;
+//		if (db_incomplete())
+//			goto swap_stree;
 		if (get_state(path_id, "path", NULL) == &ignore)
 			goto swap_stree;
 
 		return_sm = get_sm_state(RETURN_ID, "return_ranges", NULL);
+		if (local_debug)
+			sm_msg("%s: RETURN: return_sm='%s'", __func__, show_sm(return_sm));
 		if (!return_sm)
 			goto swap_stree;
 		line.value = return_sm->line;
@@ -358,6 +536,9 @@ static void check_balance(const char *name, struct symbol *sym)
 		if (!sm)
 			goto swap_stree;
 
+		// FIXME: if allocated and it's a local variable and it's not
+		// shared then it's a leak
+
 		state = sm->state;
 		if (state == &param_released)
 			state = &release;

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

  Powered by Linux