...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <threads.h> typedef struct { int balance; mtx_t balance_mutex; } bank_account; typedef struct { bank_account *from; bank_account *to; int amount; } deposit_thr_args; void create_bank_account(bank_account **ba, int initial_amount) { int result; bank_account *nba = (bank_account *) malloc(sizeof(bank_account)); if (nba == NULL) { /* Handle Error */ } nba->balance = initial_amount; result = mtx_init(&nba->balance_mutex, mtx_plain); if (result == thrd_error) { /* Handle error */ } *ba = nba; } int deposit(void *ptr) { int result; deposit_thr_args *args = (deposit_thr_args *)ptr; if ((result = mtx_lock(&(args->from->balance_mutex))) != thrd_success) { /* Handle error */ } /* not enough balance to transfer */ if (args->from->balance < args->amount) { if ((result = mtx_unlock(&(args->from->balance_mutex))) != thrd_success) { /* Handle error */ } return -1; /* Indicate error */ } if ((result = mtx_lock(&(args->to->balance_mutex))) != thrd_success) { /* Handle error */ } args->from->balance -= args->amount; args->to->balance += args->amount; if ((result = mtx_unlock(&(args->from->balance_mutex))) != thrd_success) { /* Handle error */ } if ((result = mtx_unlock(&(args->to->balance_mutex))) != thrd_success) { /* Handle error */ } free(ptr); return 0; } int main(void) { pthread_t thr1, thr2; int result; deposit_thr_args *arg1; deposit_thr_args *arg2; bank_account *ba1; bank_account *ba2; create_bank_account(&ba1, 1000); create_bank_account(&ba2, 1000); arg1 = (deposit_thr_args *arg1 = )malloc(sizeof(deposit_thr_args)); if (arg1 == NULL) { /* Handle error */ } arg2 = (deposit_thr_args *arg2 = )malloc(sizeof(deposit_thr_args)); if (arg2 == NULL) { /* Handle error */ } arg1->from = ba1; arg1->to = ba2; arg1->amount = 100; arg2->from = ba2; arg2->to = ba1; arg2->amount = 100; /* performPerform the deposits. */ if ((result = thrd_create(&thr1, deposit, (void *)arg1)) != thrd_success) { /* Handle error */ } if ((result = thrd_create(&thr2, deposit, (void *)arg2)) != thrd_success) { /* Handle error */ } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <threads.h> typedef struct { int balance; mtx_t balance_mutex; unsigned int id; /* Should never be changed after initialized. */ unsigned int id; } bank_account; unsigned int global_id = 1; void create_bank_account(bank_account **ba, int initial_amount) { int result; bank_account *nba = (bank_account *) malloc(sizeof(bank_account)); if (nba == NULL) { /* Handle error */ } nba->balance = initial_amount; result = mtx_init(&nba->balance_mutex, mtx_plain); if (result != thrd_success) { /* Handle error */ } nba->id = global_id++; *ba = nba; } int deposit(void *ptr) { deposit_thr_args *args = (deposit_thr_args *)ptr; int result, ret_val = -1; mtx_t *first; mtx_t *second; if (args->from->id == args->to->id) return -1; /* Indicate error */ /* Ensure proper ordering for locking */ if (args->from->id < args->to->id) { if ((resultfirst = mtx_lock(&(args->from->balance_mutex))) != thrd_success) {; second /* Handle error */= &args->to->balance_mutex; } else }{ iffirst ((result = mtx_lock(&(args->to->balance_mutex))) != thrd_success) {; second /* Handle error */= &args->from->balance_mutex; } } else { if ((result = mtx_lock(&(args->to->balance_mutexfirst))) != thrd_success) { /* Handle error */ } if ((result = mtx_lock(&(args->from->balance_mutex)second)) != thrd_success) { /* Handle error */ } } /* notNot enough balance to transfer. */ if (args->from->balance <>= args->amount) { if ((result = mtx_unlock(&(args->from->balance_mutex))) !-= thrd_success) { args->amount; /* Handle error */ } if ((result = mtx_unlock(&(args->to->balance_mutex))) != thrd_success) { /* Handle error */ } return -1; /* Indicate error */ } args->from->balance -= args->amount; args->to->balance += args->amount;+= args->amount; ret_val = 0; } if ((result = mtx_unlock(&(args->from->balance_mutexsecond))) != thrd_success) { /* Handle error */ } if ((result = mtx_unlock(&(args->to->balance_mutex)first)) != thrd_success) { /* Handle error */ } free(ptr); return 0ret_val; } |
Risk Assessment
Deadlock prevents multiple threads from progressing, thus halting the executing program. A denial-of-service attack is possible because the attacker can force deadlock situations. Deadlock is likely to occur in multithreaded programs that manage multiple shared resources.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
CON35-C | low | probable | medium | P4 | L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Coverity | 6.5 | DEADLOCK | Fully implemented |
...
[Barney 2010] | pthread_mutex tutorial |
[Bryant 2003] | Chapter 13, "Concurrent Programming" |
...