Valgrind says "stack allocation," I say "heap allocation"
- by Joel J. Adamson
Dear Friends,
I am trying to trace a segfault with valgrind. I get the following message from valgrind:
==3683== Conditional jump or move depends on uninitialised value(s)
==3683== at 0x4C277C5: sparse_mat_mat_kron (sparse.c:165)
==3683== by 0x4C2706E: rec_mating (rec.c:176)
==3683== by 0x401C1C: age_dep_iterate (age_dep.c:287)
==3683== by 0x4014CB: main (age_dep.c:92)
==3683== Uninitialised value was created by a stack allocation
==3683== at 0x401848: age_dep_init_params (age_dep.c:131)
==3683==
==3683== Conditional jump or move depends on uninitialised value(s)
==3683== at 0x4C277C7: sparse_mat_mat_kron (sparse.c:165)
==3683== by 0x4C2706E: rec_mating (rec.c:176)
==3683== by 0x401C1C: age_dep_iterate (age_dep.c:287)
==3683== by 0x4014CB: main (age_dep.c:92)
==3683== Uninitialised value was created by a stack allocation
==3683== at 0x401848: age_dep_init_params (age_dep.c:131)
However, here's the offending line:
/* allocate mating table */
age_dep_data->mtable = malloc (age_dep_data->geno * sizeof (double *));
if (age_dep_data->mtable == NULL)
error (ENOMEM, ENOMEM, nullmsg, __LINE__);
for (int j = 0; j < age_dep_data->geno; j++)
{
131=> age_dep_data->mtable[j] = calloc (age_dep_data->geno, sizeof (double));
if (age_dep_data->mtable[j] == NULL)
error (ENOMEM, ENOMEM, nullmsg, __LINE__);
}
What gives? I thought any call to malloc or calloc allocated heap space; there is no other variable allocated here, right? Is it possible there's another allocation going on (the offending stack allocation) that I'm not seeing?
You asked to see the code, here goes:
/*
Copyright 2010 Joel J. Adamson <adamsonj@email.unc.edu>
$Id: age_dep.c 1010 2010-04-21 19:19:16Z joel $
age_dep.c:main file
Joel J. Adamson -- http://www.unc.edu/~adamsonj
Servedio Lab
University of North Carolina at Chapel Hill
CB #3280, Coker Hall
Chapel Hill, NC 27599-3280
This file is part of an investigation of age-dependent sexual
selection.
This code is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This software is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with haploid. If not, see <http://www.gnu.org/licenses/>.
*/
#include "age_dep.h"
/* global variables */
extern struct argp age_dep_argp;
/* global error message variables */
char * nullmsg = "Null pointer: %i";
/* error message for conversions: */
char * errmsg = "Representation error: %s";
/* precision for formatted output: */
const char prec[] = "%-#9.8f ";
const size_t age_max = AGEMAX; /* maximum age of males */
static int keep_going_p = 1;
int
main (int argc, char ** argv)
{
/* often used counters: */
int i, j;
/* read the command line */
struct age_dep_args age_dep_args = { NULL, NULL, NULL };
argp_parse (&age_dep_argp, argc, argv, 0, 0, &age_dep_args);
/* set the parameters here: */
/* initialize an age_dep_params structure, set the members */
age_dep_params_t * params = malloc (sizeof (age_dep_params_t));
if (params == NULL)
error (ENOMEM, ENOMEM, nullmsg, __LINE__);
age_dep_init_params (params, &age_dep_args);
/* initialize frequencies: this initializes a list of pointers to
initial frqeuencies, terminated by a NULL pointer*/
params->freqs = age_dep_init (&age_dep_args);
params->by = 0.0;
/* what range of parameters do we want, and with what stepsize? */
/* we should go from 0 to half-of-theta with a step size of about
0.01 */
double from = 0.0;
double to = params->theta / 2.0;
double stepsz = 0.01; /* did you think I would spell the
whole word? */
unsigned int numparts = floor(to / stepsz);
do
{
#pragma omp parallel for private(i) firstprivate(params) \
shared(stepsz, numparts)
for (i = 0; i < numparts; i++)
{
params->by = i * stepsz;
int tries = 0;
while (keep_going_p)
{
/* each time through, modify mfreqs and mating table, then go
again */
keep_going_p = age_dep_iterate (params, ++tries);
if (keep_going_p == ERANGE)
error (ERANGE, ERANGE, "Failure to converge\n");
}
fprintf (stdout, "%i iterations\n", tries);
} /* for i < numparts */
params->freqs = params->freqs->next;
} while (params->freqs->next != NULL);
return 0;
}
inline double
age_dep_pmate (double age_dep_t, unsigned int genot, double bp, double ba)
{
/* the probability of mating between these phenotypes */
/* the female preference depends on whether the female has the
preference allele, the strength of preference (parameter bp) and
the male phenotype (age_dep_t); if the female lacks the
preference allele, then this will return 0, which is not quite
accurate; it should return 1 */
return bits_isset (genot, CLOCI)?
1.0 - exp (-bp * age_dep_t) + ba:
1.0;
}
inline double
age_dep_trait (int age, unsigned int genot, double by)
{
/* return the male trait, a function of the trait locus, age, the
age-dependent scaling parameter (bx) and the males condition
genotype */
double C;
double T;
/* get the male's condition genotype */
C = (double) bits_popcount (bits_extract (0, CLOCI, genot));
/* get his trait genotype */
T = bits_isset (genot, CLOCI + 1)? 1.0: 0.0;
/* return the trait value */
return T * by * exp (age * C);
}
int
age_dep_iterate (age_dep_params_t * data, unsigned int tries)
{
/* main driver routine */
/* number of bytes for female frequencies */
size_t geno = data->age_dep_data->geno;
size_t genosize = geno * sizeof (double);
/* female frequencies are equal to male frequencies at birth (before
selection) */
double ffreqs[geno];
if (ffreqs == NULL)
error (ENOMEM, ENOMEM, nullmsg, __LINE__);
/* do not set! Use memcpy (we need to alter male frequencies
(selection) without altering female frequencies) */
memmove (ffreqs, data->freqs->freqs[0], genosize);
/* for (int i = 0; i < geno; i++) */
/* ffreqs[i] = data->freqs->freqs[0][i]; */
#ifdef PRMTABLE
age_dep_pr_mfreqs (data);
#endif /* PRMTABLE */
/* natural selection: */
age_dep_ns (data);
/* normalized mating table with new frequencies */
age_dep_norm_mtable (ffreqs, data);
#ifdef PRMTABLE
age_dep_pr_mtable (data);
#endif /* PRMTABLE */
double * newfreqs;
/* mutate here */
/* i.e. get the new frequency of 0-year-olds using
recombination; */
newfreqs = rec_mating (data->age_dep_data);
/* return block */
{
if (sim_stop_ck (data->freqs->freqs[0], newfreqs, GENO, TOL) == 0)
{
/* if we have converged, stop the iterations and handle the data */
age_dep_sim_out (data, stdout);
return 0;
}
else if (tries > MAXTRIES)
return ERANGE;
else
{
/* advance generations */
for (int j = age_max - 1; j < 0; j--)
memmove (data->freqs->freqs[j],
data->freqs->freqs[j-1],
genosize);
/* advance the first age-class */
memmove (data->freqs->freqs[0], newfreqs, genosize);
return 1;
}
}
}
void
age_dep_ns (age_dep_params_t * data)
{
/* calculate the new frequency of genotypes given additive fitness
and selection coefficient s */
size_t geno = data->age_dep_data->geno;
double w[geno];
double wbar, dtheta, ttheta, dcond, tcond;
double t, cond;
/* fitness parameters */
double mu, nu;
mu = data->wparams[0];
nu = data->wparams[1];
/* calculate fitness */
for (int j = 0; j < age_max; j++)
{
int i;
for (i = 0; i < geno; i++)
{
/* calculate male trait: */
t = age_dep_trait(j, i, data->by);
/* calculate condition: */
cond = (double) bits_popcount (bits_extract(0, CLOCI, i));
/* trait-based fitness term */
dtheta = data->theta - t;
ttheta = (dtheta * dtheta) / (2.0 * nu * nu);
/* condition-based fitness term */
dcond = CLOCI - cond;
tcond = (dcond * dcond) / (2.0 * mu * mu);
/* calculate male fitness */
w[i] = 1 + exp(-tcond) - exp(-ttheta);
}
/* calculate mean fitness */
/* as long as we calculate wbar before altering any values of
freqs[], we're safe */
wbar = gen_mean (data->freqs->freqs[j], w, geno);
for (i = 0; i < geno; i++)
data->freqs->freqs[j][i] =
(data->freqs->freqs[j][i] * w[i]) / wbar;
}
}
void
age_dep_norm_mtable (double * ffreqs, age_dep_params_t * params)
{
/* this function produces a single mating table that forms the input
for recombination () */
/* i is female genotype; j is male genotype; k is male age */
int i,j,k;
double norm_denom;
double trait;
size_t geno = params->age_dep_data->geno;
for (i = 0; i < geno; i++)
{
double norm_mtable[geno];
/* initialize the denominator: */
norm_denom = 0.0;
/* find the probability of mating and add it to the denominator */
for (j = 0; j < geno; j++)
{
/* initialize entry: */
norm_mtable[j] = 0.0;
for (k = 0; k < age_max; k++)
{
trait = age_dep_trait (k, j, params->by);
norm_mtable[j] +=
age_dep_pmate (trait, i, params->bp, params->ba)
* (params->freqs->freqs)[k][j];
}
norm_denom += norm_mtable[j];
}
/* now calculate entry (i,j) */
for (j = 0; j < geno; j++)
params->age_dep_data->mtable[i][j]
= (ffreqs[i] * norm_mtable[j]) / norm_denom;
}
}
My current suspicion is the array newfreqs: I can't memmove, memcpy or assign a stack variable then hope it will persist, can I? rec_mating() returns double *.