diff options
Diffstat (limited to 'gmon/gmon.c')
-rw-r--r-- | gmon/gmon.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/gmon/gmon.c b/gmon/gmon.c index 689bf80141..5e99a7351d 100644 --- a/gmon/gmon.c +++ b/gmon/gmon.c @@ -102,11 +102,8 @@ __moncontrol (int mode) { struct gmonparam *p = &_gmonparam; - /* Don't change the state if we ran into an error. */ - if (p->state == GMON_PROF_ERROR) - return; - - if (mode) + /* Treat start request as stop if error or gmon not initialized. */ + if (mode && p->state != GMON_PROF_ERROR && p->tos != NULL) { /* start */ __profil((void *) p->kcount, p->kcountsize, p->lowpc, s_scale); @@ -116,7 +113,9 @@ __moncontrol (int mode) { /* stop */ __profil(NULL, 0, 0, 0); - p->state = GMON_PROF_OFF; + /* Don't change the state if we ran into an error. */ + if (p->state != GMON_PROF_ERROR) + p->state = GMON_PROF_OFF; } } libc_hidden_def (__moncontrol) @@ -147,6 +146,14 @@ __monstartup (u_long lowpc, u_long highpc) #endif /* + * If we are incorrectly called twice in a row (without an + * intervening call to _mcleanup), ignore the second call to + * prevent leaking memory. + */ + if (p->tos != NULL) + return; + + /* * round lowpc and highpc to multiples of the density we're using * so the rest of the scaling (here and in gprof) stays in ints. */ @@ -463,9 +470,14 @@ _mcleanup (void) { __moncontrol (0); - if (_gmonparam.state != GMON_PROF_ERROR) + if (_gmonparam.state != GMON_PROF_ERROR && _gmonparam.tos != NULL) write_gmon (); /* free the memory. */ free (_gmonparam.tos); + + /* reset buffer to initial state for safety */ + memset(&_gmonparam, 0, sizeof _gmonparam); + /* somewhat confusingly, ON=0, OFF=3 */ + _gmonparam.state = GMON_PROF_OFF; } |