4
4
#define MAX_ALLOCS 10000
5
5
const u64 linear_set_size_increment = 1000000 ;
6
6
7
+
8
+
9
+ typedef enum LockWritability {
10
+ WriteHeld ,
11
+ ReadHeld ,
12
+ } LockWritability ;
13
+
14
+ typedef struct LockAccess {
15
+ LockWritability state ;
16
+ usize addr ;
17
+ u64 callee_thread_id ;
18
+ } LockAccess ;
19
+
20
+
7
21
// todo => shrink to 8 bytes. Should be possible if memory address access/accessing only store
8
22
// bytes of the virtual address that define the memory locations relative to the process pages)
9
23
// reference: https://developer.arm.com/documentation/den0024/a/The-Memory-Management-Unit/Translating-a-Virtual-Address-to-a-Physical-Address
@@ -14,12 +28,10 @@ typedef struct MemoryAccess {
14
28
u64 size ;
15
29
u64 callee_thread_id ;
16
30
u64 memory_access_count ;
31
+ u32 has_lock ;
32
+ LockAccess lock_access ;
17
33
} MemoryAccess ;
18
34
19
- typedef enum LockWritability {
20
- WriteHeld ,
21
- ReadHeld ,
22
- } LockWritability ;
23
35
24
36
typedef struct LockState {
25
37
LockWritability state ;
@@ -30,13 +42,6 @@ typedef struct LockState {
30
42
} LockState ;
31
43
32
44
33
- typedef struct LockAccess {
34
- LockWritability state ;
35
- usize addr ;
36
- u64 callee_thread_id ;
37
- u64 memory_access_count ;
38
- } LockAccess ;
39
-
40
45
typedef struct MemoryAllocation {
41
46
usize addr ;
42
47
u64 size ;
@@ -54,20 +59,16 @@ typedef struct ThreadState {
54
59
u64 mem_write_set_capacity ;
55
60
u64 mem_write_set_len ;
56
61
57
-
58
62
LockState * lock_state_set ;
59
63
u64 lock_state_set_capacity ;
60
64
u64 lock_state_set_len ;
61
65
62
- LockAccess * lock_write_held_set ;
63
- u64 lock_write_held_set_capacity ;
64
- u64 lock_write_held_set_len ;
65
-
66
- LockAccess * lock_read_held_set ;
67
- u64 lock_read_held_set_capacity ;
68
- u64 lock_read_held_set_len ;
66
+ usize last_locked_mutex_addr ;
69
67
} ThreadState ;
70
68
69
+ usize debug_ok_checks = 0 ;
70
+ usize debug_error_checks = 0 ;
71
+
71
72
72
73
// max allocations is seperate from thread state since it needs to be itreated thorugh on every error check
73
74
MemoryAllocation allocations [MAX_ALLOCS ] = {};
@@ -95,15 +96,15 @@ i64 find_thread_by_tid(u64 tid) {
95
96
return -1 ;
96
97
}
97
98
98
- i64 find_lockset_by_memory_access_count (LockAccess * lock_set , u64 lock_set_len , u64 access_count ) {
99
- u64 i ;
100
- for (i = 0 ; i <= lock_set_len ; i ++ ) {
101
- if (lock_set [i ].memory_access_count == access_count ) {
102
- return i ;
103
- }
104
- }
105
- return -1 ;
106
- }
99
+ // i64 find_lockset_by_memory_access_count(LockAccess *lock_set, u64 lock_set_len, u64 access_count) {
100
+ // u64 i;
101
+ // for (i = 0; i <= lock_set_len; i++) {
102
+ // if (lock_set[i].memory_access_count == access_count) {
103
+ // return i;
104
+ // }
105
+ // }
106
+ // return -1;
107
+ // }
107
108
108
109
u32 is_in_range (u64 num , u64 min , u64 max ) {
109
110
return (min <= num && num <= max );
@@ -118,18 +119,18 @@ void mem_analyse_exit() {
118
119
printf ("mem_write_set_len: %ld \n" , threads [j ].mem_write_set_len );
119
120
printf ("mem_read_set_len: %ld \n" , threads [j ].mem_read_set_len );
120
121
printf ("lock_state_set_len: %ld \n" , threads [j ].lock_state_set_len );
121
-
122
+
122
123
u64 i ;
124
+ printf ("locks: \n" );
123
125
for (i = 0 ; i <= threads [j ].lock_state_set_len ; i ++ ) {
124
- printf ("lock %ld, state: %d \n" , threads [j ].lock_state_set [i ].addr , threads [j ].lock_state_set [i ].state );
126
+ printf ("lock addr: %ld, (end) state: %d \n" , threads [j ].lock_state_set [i ].addr , threads [j ].lock_state_set [i ].state );
125
127
}
126
128
127
129
free (threads [j ].mem_write_set );
128
130
free (threads [j ].mem_read_set );
129
131
free (threads [j ].lock_state_set );
130
- free (threads [j ].lock_write_held_set );
131
- free (threads [j ].lock_read_held_set );
132
132
}
133
+ printf ("debug error checks: %ld, ok checks: %ld \n" , debug_error_checks , debug_ok_checks );
133
134
}
134
135
135
136
u32 mem_analyse_init () {
@@ -163,20 +164,6 @@ u32 mem_analyse_new_thread_init(void *drcontext) {
163
164
return 0 ;
164
165
}
165
166
166
- threads [n_threads ].lock_write_held_set = (LockAccess * )malloc (sizeof (LockAccess ) * linear_set_size_increment );
167
- threads [n_threads ].lock_write_held_set_capacity = linear_set_size_increment ;
168
- if (threads [n_threads ].lock_write_held_set == NULL ) {
169
- printf ("set allocation error \n" );
170
- return 0 ;
171
- }
172
-
173
- threads [n_threads ].lock_read_held_set = (LockAccess * )malloc (sizeof (LockAccess ) * linear_set_size_increment );
174
- threads [n_threads ].lock_read_held_set_capacity = linear_set_size_increment ;
175
- if (threads [n_threads ].lock_read_held_set == NULL ) {
176
- printf ("set allocation error \n" );
177
- return 0 ;
178
- }
179
-
180
167
n_threads += 1 ;
181
168
return 1 ;
182
169
}
@@ -239,19 +226,10 @@ void wrap_pre_lock(void *wrapcxt, OUT void **user_data) {
239
226
};
240
227
}
241
228
thread_accessed -> lock_state_set [i ].lock_count += 1 ;
242
- if (thread_accessed -> lock_state_set [i ].lock_count >= thread_accessed -> lock_state_set [i ].lock_count ) {
243
- // now the lock is write held
244
- thread_accessed -> lock_write_held_set [thread_accessed -> lock_write_held_set_len ].addr = (usize ) addr ;
245
- thread_accessed -> lock_write_held_set [thread_accessed -> lock_write_held_set_len ].callee_thread_id = thread_id ;
246
- thread_accessed -> lock_write_held_set [thread_accessed -> lock_write_held_set_len ].memory_access_count = memory_access_counter ;
247
- thread_accessed -> lock_write_held_set_len += 1 ;
248
- } else {
249
- // read held
250
- thread_accessed -> lock_read_held_set [thread_accessed -> lock_read_held_set_len ].addr = (usize ) addr ;
251
- thread_accessed -> lock_read_held_set [thread_accessed -> lock_read_held_set_len ].callee_thread_id = thread_id ;
252
- thread_accessed -> lock_read_held_set [thread_accessed -> lock_read_held_set_len ].memory_access_count = memory_access_counter ;
253
- thread_accessed -> lock_read_held_set_len += 1 ;
229
+ if (thread_accessed -> lock_state_set [i ].unlock_count <= thread_accessed -> lock_state_set [i ].lock_count ) {
230
+ thread_accessed -> lock_state_set [i ].state = WriteHeld ;
254
231
}
232
+ thread_accessed -> last_locked_mutex_addr = (usize )addr ;
255
233
}
256
234
257
235
void wrap_post_malloc (void * wrapcxt , void * user_data ) {
@@ -268,7 +246,6 @@ void wrap_post_malloc(void *wrapcxt, void *user_data) {
268
246
if (threads [j ].thread_id == thread_id ) break ;
269
247
if (j == n_threads - 1 ) return ;
270
248
}
271
- // printf("ADDED %ld \n", thread_id);
272
249
allocations [n_allocs ].addr = (usize )addr ;
273
250
allocations [n_allocs ].callee_thread_id = thread_id ;
274
251
allocations [n_allocs ].size = size ;
@@ -280,14 +257,25 @@ void wrap_pre_malloc(void *wrapcxt, OUT void **user_data) {
280
257
}
281
258
282
259
void check_for_race (ThreadState * thread_state ) {
283
- int write_set_i , read_set_i , lock_set_i1 , lock_set_i2 ;
260
+ int write_set_i , read_set_i ;
284
261
for (write_set_i = 0 ; write_set_i <= thread_state -> mem_write_set_len ; write_set_i ++ ) {
285
262
for (read_set_i = 0 ; read_set_i <= thread_state -> mem_read_set_len ; read_set_i ++ ) {
263
+ // check write-read pairs
286
264
if (thread_state -> mem_write_set [write_set_i ].memory_access_count > thread_state -> mem_read_set [read_set_i ].memory_access_count ) {
287
- if (find_lockset_by_memory_access_count (thread_state -> lock_write_held_set , thread_state -> lock_write_held_set_len , thread_state -> lock_write_held_set [write_set_i ].memory_access_count ) == -1 || find_lockset_by_memory_access_count (thread_state -> lock_write_held_set , thread_state -> lock_write_held_set_len , thread_state -> mem_read_set [read_set_i ].memory_access_count ) == -1 ) {
288
- printf ("FOUND!\n" );
265
+ if (!thread_state -> mem_write_set [write_set_i ].has_lock && !thread_state -> mem_read_set [write_set_i ].has_lock ) {
266
+ // printf("found read race for addr: %ld in thread: %ld \n", thread_state->mem_write_set[write_set_i].address_accessed, thread_state->mem_write_set[write_set_i].callee_thread_id);
267
+ debug_error_checks += 1 ;
268
+ } else {
269
+ debug_ok_checks += 1 ;
289
270
}
290
271
}
272
+ // write write-read pairs
273
+ if (!thread_state -> mem_write_set [write_set_i ].has_lock && !thread_state -> mem_write_set [write_set_i + 1 ].has_lock ) {
274
+ // printf("found write race for addr: %ld in thread: %ld \n", thread_state->mem_write_set[write_set_i].address_accessed, thread_state->mem_write_set[write_set_i].callee_thread_id);
275
+ debug_error_checks += 1 ;
276
+ } else {
277
+ debug_ok_checks += 1 ;
278
+ }
291
279
}
292
280
}
293
281
}
@@ -311,7 +299,8 @@ void memtrace(void *drcontext, u64 thread_id) {
311
299
for (j = 0 ; j < n_allocs ; j ++ ) {
312
300
if (is_in_range ((usize )mem_ref -> addr , allocations [j ].addr , allocations [j ].addr + allocations [j ].size )) break ;
313
301
314
- if (j >= n_allocs - 1 ) {
302
+ if (j >= n_allocs - 1 || n_allocs == 0 ) {
303
+ // printf("not found \n");
315
304
// commiting a sin but goto is the most simple way to continue an outer loop in C
316
305
goto continue_outer_loop ;
317
306
}
@@ -333,7 +322,14 @@ void memtrace(void *drcontext, u64 thread_id) {
333
322
return ;
334
323
}
335
324
ThreadState * thread_accessed = & threads [thread_states_index_owning_accessed_addr ];
336
- // printf("adding %d \n", thread_states_index_owning_accessed_addr);
325
+
326
+ i32 lock_state_i ;
327
+ for (lock_state_i = 0 ; lock_state_i <= thread_accessed -> lock_state_set_len ; lock_state_i ++ ) {
328
+ if (thread_accessed -> lock_state_set [lock_state_i ].addr == thread_accessed -> last_locked_mutex_addr ) {
329
+ break ;
330
+ }
331
+ if (lock_state_i >= thread_accessed -> lock_state_set_len ) lock_state_i = -1 ;
332
+ }
337
333
if (mem_ref -> type == 1 || mem_ref -> type == 457 || mem_ref -> type == 458 || mem_ref -> type == 456 || mem_ref -> type == 568 ) {
338
334
// mem write
339
335
if (thread_accessed -> mem_write_set_len >= thread_accessed -> mem_write_set_capacity ) thread_accessed -> mem_write_set = increase_set_capacity (thread_accessed -> mem_write_set , & thread_accessed -> mem_write_set_capacity );
@@ -343,6 +339,11 @@ void memtrace(void *drcontext, u64 thread_id) {
343
339
thread_accessed -> mem_write_set [thread_accessed -> mem_write_set_len ].callee_thread_id = thread_id ;
344
340
thread_accessed -> mem_write_set [thread_accessed -> mem_write_set_len ].size = mem_ref -> size ;
345
341
thread_accessed -> mem_write_set [thread_accessed -> mem_write_set_len ].memory_access_count = memory_access_counter ;
342
+ if (lock_state_i != -1 ) {
343
+ LockAccess la = {thread_accessed -> lock_state_set [lock_state_i ].state , thread_accessed -> lock_state_set [lock_state_i ].addr , thread_accessed -> lock_state_set [lock_state_i ].callee_thread_id };
344
+ thread_accessed -> mem_write_set [thread_accessed -> mem_read_set_len ].lock_access = la ;
345
+ thread_accessed -> mem_write_set [thread_accessed -> mem_read_set_len ].has_lock = 1 ;
346
+ }
346
347
thread_accessed -> mem_write_set_len += 1 ;
347
348
} else if (mem_ref -> type == 0 || mem_ref -> type == 227 || mem_ref -> type == 225 || mem_ref -> type == 197 || mem_ref -> type == 228 || mem_ref -> type == 229 || mem_ref -> type == 299 || mem_ref -> type == 173 ) {
348
349
// mem read
@@ -353,6 +354,11 @@ void memtrace(void *drcontext, u64 thread_id) {
353
354
thread_accessed -> mem_read_set [thread_accessed -> mem_read_set_len ].callee_thread_id = thread_id ;
354
355
thread_accessed -> mem_read_set [thread_accessed -> mem_read_set_len ].size = mem_ref -> size ;
355
356
thread_accessed -> mem_read_set [thread_accessed -> mem_read_set_len ].memory_access_count = memory_access_counter ;
357
+ if (lock_state_i != -1 ) {
358
+ LockAccess la = {thread_accessed -> lock_state_set [lock_state_i ].state , thread_accessed -> lock_state_set [lock_state_i ].addr , thread_accessed -> lock_state_set [lock_state_i ].callee_thread_id };
359
+ thread_accessed -> mem_read_set [thread_accessed -> mem_read_set_len ].lock_access = la ;
360
+ thread_accessed -> mem_read_set [thread_accessed -> mem_read_set_len ].has_lock = 1 ;
361
+ }
356
362
thread_accessed -> mem_read_set_len += 1 ;
357
363
}
358
364
check_for_race (thread_accessed );
0 commit comments