Browse Source

Track all dynamically allocated memory within the work struct by copying work structs in a common place, creating freshly allocated heap ram for all arrays within the copied struct.

Clear all work structs from the same place to ensure memory does not leak from arrays within the struct.
Convert the gbt coinbase and stratum strings within the work struct to heap ram.
This will allow arbitrary lengths without an upper limit for the strings, preventing the overflows that happen with GBT.
nfactor-troky
Con Kolivas 12 years ago
parent
commit
2d35ac2567
  1. 98
      cgminer.c
  2. 2
      driver-modminer.c
  3. 7
      driver-opencl.c
  4. 14
      miner.h

98
cgminer.c

@ -239,7 +239,7 @@ int swork_id; @@ -239,7 +239,7 @@ int swork_id;
struct stratum_share {
UT_hash_handle hh;
bool block;
struct work work;
struct work *work;
int id;
};
@ -1469,9 +1469,7 @@ static void calc_diff(struct work *work, int known); @@ -1469,9 +1469,7 @@ static void calc_diff(struct work *work, int known);
static void gen_gbt_work(struct pool *pool, struct work *work)
{
unsigned char *merkleroot;
char *cbhex;
memset(work->job_id, 0, 64);
mutex_lock(&pool->gbt_lock);
__build_gbt_coinbase(pool);
merkleroot = __gbt_merkleroot(pool);
@ -1483,15 +1481,13 @@ static void gen_gbt_work(struct pool *pool, struct work *work) @@ -1483,15 +1481,13 @@ static void gen_gbt_work(struct pool *pool, struct work *work)
memcpy(work->target, pool->gbt_target, 32);
cbhex = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
sprintf(work->gbt_coinbase, "%s", cbhex);
free(cbhex);
work->gbt_coinbase = bin2hex(pool->gbt_coinbase, pool->coinbase_len);
/* For encoding the block data on submission */
work->gbt_txns = pool->gbt_txns + 1;
if (pool->gbt_workid)
sprintf(work->job_id, "%s", pool->gbt_workid);
work->job_id = strdup(pool->gbt_workid);
mutex_unlock(&pool->gbt_lock);
memcpy(work->data + 4 + 32, merkleroot, 32);
@ -2307,7 +2303,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) @@ -2307,7 +2303,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
/* build JSON-RPC request */
if (work->gbt) {
char gbt_block[1024], *varint, *header;
char gbt_block[4096], *varint, *header;
unsigned char data[80];
flip80(data, work->data);
@ -2334,7 +2330,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit) @@ -2334,7 +2330,7 @@ static bool submit_upstream_work(struct work *work, CURL *curl, bool resubmit)
free(varint);
strcat(gbt_block, work->gbt_coinbase);
if (strlen(work->job_id))
if (work->job_id)
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {\"workid\": \"%s\"}]}", gbt_block, work->job_id);
else
sprintf(s, "{\"id\": 0, \"method\": \"submitblock\", \"params\": [\"%s\", {}]}", gbt_block);
@ -2634,8 +2630,25 @@ static struct work *make_work(void) @@ -2634,8 +2630,25 @@ static struct work *make_work(void)
return work;
}
static void free_work(struct work *work)
/* This is the central place all work that is about to be retired should be
* cleaned to remove any dynamically allocated arrays within the struct */
void clean_work(struct work *work)
{
free(work->job_id);
free(work->nonce2);
free(work->ntime);
free(work->gbt_coinbase);
work->job_id = NULL;
work->nonce2 = NULL;
work->ntime = NULL;
work->gbt_coinbase = NULL;
}
/* All dynamically allocated work structs should be freed here to not leak any
* ram from arrays allocated within the work struct */
void free_work(struct work *work)
{
clean_work(work);
free(work);
}
@ -2948,11 +2961,37 @@ static void roll_work(struct work *work) @@ -2948,11 +2961,37 @@ static void roll_work(struct work *work)
work->id = total_work++;
}
/* Duplicates any dynamically allocated arrays within the work struct to
* prevent a copied work struct from freeing ram belonging to another struct */
void __copy_work(struct work *work, struct work *base_work)
{
clean_work(work);
memcpy(work, base_work, sizeof(struct work));
if (work->job_id)
work->job_id = strdup(base_work->job_id);
if (work->nonce2)
work->nonce2 = strdup(base_work->nonce2);
if (work->ntime)
work->ntime = strdup(base_work->ntime);
if (work->gbt_coinbase)
work->gbt_coinbase = strdup(base_work->gbt_coinbase);
}
/* Generates a copy of an existing work struct, creating fresh heap allocations
* for all dynamically allocated arrays within the struct */
struct work *copy_work(struct work *base_work)
{
struct work *work = make_work();
__copy_work(work, base_work);
return work;
}
static struct work *make_clone(struct work *work)
{
struct work *work_clone = make_work();
struct work *work_clone = copy_work(work);
memcpy(work_clone, work, sizeof(struct work));
work_clone->clone = true;
gettimeofday((struct timeval *)&(work_clone->tv_cloned), NULL);
work_clone->longpoll = false;
@ -3016,7 +3055,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work); @@ -3016,7 +3055,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work);
static void *get_work_thread(void *userdata)
{
struct workio_cmd *wc = (struct workio_cmd *)userdata;
struct work *ret_work= NULL;
struct work *ret_work = NULL;
struct curl_ent *ce = NULL;
struct pool *pool;
@ -3232,7 +3271,7 @@ static void *submit_work_thread(void *userdata) @@ -3232,7 +3271,7 @@ static void *submit_work_thread(void *userdata)
char *noncehex;
char s[1024];
memcpy(&sshare->work, work, sizeof(struct work));
sshare->work = copy_work(work);
mutex_lock(&sshare_lock);
/* Give the stratum share a unique id */
sshare->id = swork_id++;
@ -4538,7 +4577,7 @@ out_unlock: @@ -4538,7 +4577,7 @@ out_unlock:
static void stratum_share_result(json_t *val, json_t *res_val, json_t *err_val,
struct stratum_share *sshare)
{
struct work *work = &sshare->work;
struct work *work = sshare->work;
uint64_t sharediff = share_diff(work);
char hashshow[65];
uint32_t *hash32;
@ -4602,6 +4641,7 @@ static bool parse_stratum_response(struct pool *pool, char *s) @@ -4602,6 +4641,7 @@ static bool parse_stratum_response(struct pool *pool, char *s)
goto out;
}
stratum_share_result(val, res_val, err_val, sshare);
free_work(sshare->work);
free(sshare);
ret = true;
@ -4621,8 +4661,9 @@ static void clear_stratum_shares(struct pool *pool) @@ -4621,8 +4661,9 @@ static void clear_stratum_shares(struct pool *pool)
mutex_lock(&sshare_lock);
HASH_ITER(hh, stratum_shares, sshare, tmpshare) {
if (sshare->work.pool == pool) {
if (sshare->work->pool == pool) {
HASH_DEL(stratum_shares, sshare);
free_work(sshare->work);
free(sshare);
cleared++;
}
@ -5129,17 +5170,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work) @@ -5129,17 +5170,13 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
{
unsigned char *coinbase, merkle_root[32], merkle_sha[64], *merkle_hash;
int len, cb1_len, n1_len, cb2_len, i;
char header[260], *nonce2;
uint32_t *data32, *swap32;
memset(work->job_id, 0, 64);
memset(work->nonce2, 0, 64);
memset(work->ntime, 0, 16);
char header[260];
mutex_lock(&pool->pool_lock);
/* Generate coinbase */
nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
work->nonce2 = bin2hex((const unsigned char *)&pool->nonce2, pool->n2size);
pool->nonce2++;
cb1_len = strlen(pool->swork.coinbase1) / 2;
n1_len = strlen(pool->nonce1) / 2;
@ -5148,7 +5185,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work) @@ -5148,7 +5185,7 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
coinbase = alloca(len + 1);
hex2bin(coinbase, pool->swork.coinbase1, cb1_len);
hex2bin(coinbase + cb1_len, pool->nonce1, n1_len);
hex2bin(coinbase + cb1_len + n1_len, nonce2, pool->n2size);
hex2bin(coinbase + cb1_len + n1_len, work->nonce2, pool->n2size);
hex2bin(coinbase + cb1_len + n1_len + pool->n2size, pool->swork.coinbase2, cb2_len);
/* Generate merkle root */
@ -5181,10 +5218,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work) @@ -5181,10 +5218,8 @@ static void gen_stratum_work(struct pool *pool, struct work *work)
work->sdiff = pool->swork.diff;
/* Copy parameters required for share submission */
sprintf(work->job_id, "%s", pool->swork.job_id);
sprintf(work->nonce2, "%s", nonce2);
sprintf(work->ntime, "%s", pool->swork.ntime);
free(nonce2);
work->job_id = strdup(pool->swork.job_id);
work->ntime = strdup(pool->swork.ntime);
mutex_unlock(&pool->pool_lock);
@ -5225,6 +5260,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id) @@ -5225,6 +5260,8 @@ static void get_work(struct work *work, struct thr_info *thr, const int thr_id)
* should not be restarted */
thread_reportout(thr);
clean_work(work);
if (opt_benchmark) {
get_benchmark_work(work);
goto out;
@ -5298,7 +5335,7 @@ retry: @@ -5298,7 +5335,7 @@ retry:
pool_resus(pool);
}
memcpy(work, work_heap, sizeof(struct work));
__copy_work(work, work_heap);
free_work(work_heap);
out:
@ -5307,7 +5344,7 @@ out: @@ -5307,7 +5344,7 @@ out:
work->mined = true;
}
bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct timeval *tv_work_found)
bool submit_work_sync(struct thr_info *thr, struct work *work_in, struct timeval *tv_work_found)
{
struct workio_cmd *wc;
@ -5318,10 +5355,9 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct t @@ -5318,10 +5355,9 @@ bool submit_work_sync(struct thr_info *thr, const struct work *work_in, struct t
return false;
}
wc->work = make_work();
wc->work = copy_work(work_in);
wc->cmd = WC_SUBMIT_WORK;
wc->thr = thr;
memcpy(wc->work, work_in, sizeof(*work_in));
if (tv_work_found)
memcpy(&(wc->work->tv_work_found), tv_work_found, sizeof(struct timeval));

2
driver-modminer.c

@ -645,7 +645,7 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_ @@ -645,7 +645,7 @@ static int64_t modminer_scanhash(struct thr_info *thr, struct work *work, int64_
if (startwork) {
if (!modminer_start_work(thr))
return -1;
memcpy(&state->running_work, work, sizeof(state->running_work));
__copy_work(&state->running_work, work);
}
// This is intentionally early

7
driver-opencl.c

@ -1464,10 +1464,8 @@ static void opencl_free_work(struct thr_info *thr, struct work *work) @@ -1464,10 +1464,8 @@ static void opencl_free_work(struct thr_info *thr, struct work *work)
clFinish(clState->commandQueue);
if (thrdata->res[FOUND]) {
thrdata->last_work = &thrdata->_last_work;
memcpy(thrdata->last_work, work, sizeof(*thrdata->last_work));
}
if (thrdata->res[FOUND])
thrdata->last_work = copy_work(&thrdata->_last_work);
}
static bool opencl_prepare_work(struct thr_info __maybe_unused *thr, struct work *work)
@ -1535,6 +1533,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work, @@ -1535,6 +1533,7 @@ static int64_t opencl_scanhash(struct thr_info *thr, struct work *work,
if (unlikely(thrdata->last_work)) {
applog(LOG_DEBUG, "GPU %d found something in last work?", gpu->device_id);
postcalc_hash_async(thr, thrdata->last_work, thrdata->res);
free_work(thrdata->last_work);
thrdata->last_work = NULL;
} else {
applog(LOG_DEBUG, "GPU %d found something?", gpu->device_id);

14
miner.h

@ -962,15 +962,13 @@ struct work { @@ -962,15 +962,13 @@ struct work {
bool queued;
bool stratum;
/* These are arbitrary lengths as it is too hard to keep track of
* dynamically allocated ram in work structs */
char job_id[64];
char nonce2[64];
char ntime[16];
char *job_id;
char *nonce2;
char *ntime;
double sdiff;
bool gbt;
char gbt_coinbase[512];
char *gbt_coinbase;
int gbt_txns;
unsigned int work_block;
@ -1031,6 +1029,10 @@ extern void tq_thaw(struct thread_q *tq); @@ -1031,6 +1029,10 @@ extern void tq_thaw(struct thread_q *tq);
extern bool successful_connect;
extern void adl(void);
extern void app_restart(void);
extern void clean_work(struct work *work);
extern void free_work(struct work *work);
extern void __copy_work(struct work *work, struct work *base_work);
extern struct work *copy_work(struct work *base_work);
enum api_data_type {
API_ESCAPE,

Loading…
Cancel
Save