sm_math1: update the validation test
[smatch.git] / smatch_locking_type.c
blob90f79be5df82e6401880b7da43d46099805c8848
1 /*
2 * Copyright 2024 Linaro Ltd.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
18 #include "smatch.h"
19 #include "smatch_extra.h"
20 #include "smatch_slist.h"
22 static int my_id;
24 STATE(lock);
25 STATE(unlock);
27 static struct smatch_state *get_opposite(struct smatch_state *state)
29 if (state == &lock)
30 return &unlock;
31 if (state == &unlock)
32 return &lock;
33 return NULL;
36 static struct stree *start_states;
38 static void set_start_state(const char *name, struct smatch_state *start)
40 struct smatch_state *orig;
42 if (!name || !start)
43 return;
45 if (get_state(my_id, name, NULL))
46 return;
48 orig = get_state_stree(start_states, my_id, name, NULL);
49 if (!orig)
50 set_state_stree(&start_states, my_id, name, NULL, start);
51 else if (orig != start)
52 set_state_stree(&start_states, my_id, name, NULL, &undefined);
55 static struct smatch_state *get_start_state(struct sm_state *sm)
57 struct smatch_state *orig;
59 if (!sm)
60 return NULL;
62 orig = get_state_stree(start_states, my_id, sm->name, sm->sym);
63 if (orig)
64 return orig;
65 return NULL;
68 static void update_state(const char *member, struct smatch_state *state)
70 set_start_state(member, get_opposite(state));
71 set_state(my_id, member, NULL, state);
74 static void update_expr(struct expression *expr, struct smatch_state *state)
76 char *member;
78 if (!expr)
79 return;
80 if (expr->type == EXPR_PREOP && expr->op == '&')
81 expr = strip_expr(expr->unop);
83 member = get_member_name(expr);
84 if (!member)
85 return;
87 update_state(member, state);
90 static void lock_hook(struct lock_info *info, struct expression *expr, const char *name, struct symbol *sym)
92 update_expr(expr, &lock);
95 static void unlock_hook(struct lock_info *info, struct expression *expr, const char *name, struct symbol *sym)
97 update_expr(expr, &unlock);
100 bool locking_type_is_start_state(void)
102 struct sm_state *sm;
103 int cnt;
105 cnt = 0;
106 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
107 if (++cnt > 1)
108 return false;
109 if (sm->state != get_start_state(sm))
110 return false;
111 } END_FOR_EACH_SM(sm);
113 return cnt == 1;
116 static int get_db_type(struct sm_state *sm)
118 if (sm->state == &lock)
119 return TYPE_LOCK2;
120 if (sm->state == &unlock)
121 return TYPE_UNLOCK2;
123 return -1;
126 static bool is_clean_transition(struct sm_state *sm)
128 struct smatch_state *start;
130 start = get_start_state(sm);
131 if (!start)
132 return false;
133 if (start == get_opposite(sm->state))
134 return true;
135 return false;
138 static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
140 struct sm_state *sm;
141 int type;
143 FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
144 type = get_db_type(sm);
145 if (local_debug)
146 sm_msg("%s: type=%d sm='%s' clean=%d", __func__,
147 type, show_sm(sm), is_clean_transition(sm));
148 if (type == -1)
149 continue;
151 if (!is_clean_transition(sm))
152 continue;
154 sql_insert_return_states(return_id, return_ranges, type,
155 -2, sm->name, "");
156 } END_FOR_EACH_SM(sm);
159 static void db_param_locked(struct expression *expr, int param, char *key, char *value)
161 while (expr && expr->type == EXPR_ASSIGNMENT)
162 expr = strip_expr(expr->right);
163 if (expr && expr->type == EXPR_CALL && is_locking_primitive_expr(expr->fn))
164 return;
166 update_state(key, &lock);
169 static void db_param_unlocked(struct expression *expr, int param, char *key, char *value)
171 while (expr && expr->type == EXPR_ASSIGNMENT)
172 expr = strip_expr(expr->right);
173 if (expr && expr->type == EXPR_CALL && is_locking_primitive_expr(expr->fn))
174 return;
176 update_state(key, &unlock);
179 void register_locking_type(int id)
181 my_id = id;
183 add_function_data((unsigned long *)&start_states);
185 add_lock_hook(&lock_hook);
186 add_unlock_hook(&unlock_hook);
187 add_restore_hook(&unlock_hook);
189 select_return_states_hook(TYPE_LOCK2, &db_param_locked);
190 select_return_states_hook(TYPE_UNLOCK2, &db_param_unlocked);
192 add_split_return_callback(match_return_info);