lunes, 25 de mayo de 2015

Detección de memory leaks - Parte IV (MTA)

En la entrada anterior (III) vimos como detectar memory leaks utilizando discover en una aplicación que ha sido desarrollada utilizando el framework MTA de BRM. Ahora veremos como hacerlo con otra herramienta: dbx (ésto también sirve para apliaciones que no han sido desarrolladas utilizando MTA, pero el post está orientado a este tipo de aplicaciones).
El objetivo es detectar los memory leaks y la idea es que ademas de detectarlos sepamos en que archivo y en que línea están. Para ello hay que compilar con la opcion -g para ver el código fuente para cada funcion en el stack trace.

En las entradas anteriores de detección de memory leak (I y II) se recomendó setear las variables de ambiente LD_PRELOAD y LD_AUDIT en el .profile, dbx no funcionará adecuadamente si éstas 2 variables estan seteadas.

Ejemplo paso a paso: (Código fuente del archivo basic_mta.c y del Makefile al final del post)
  1. Remover las variables de ambiente LD_PRELOAD y LD_AUDIT.
         unset LD_PRELOAD
         unset LD_AUDIT
  2. Compilar utilizando la opción -g (en el Makefile del ejemplo nuestro programa se llamará basic_mta) y si no estamos compilando con gcc usar tambien la opción -O o la opcion -xO[n]
         make clobber all
  3. Ejecutar dbx con nuestro ejecutable como parámetro:
    dbx basic_mta 
  4. En caso de que nuestro ejecutable reciba parámetros por línea de comandos:
    dbx -c "runargs -param1 valor1 -parm2 valor2" basic_mta
  5. Ya dentro del dbx ejecutar:
    check -memuse
    dbxenv rtc_mel_at_exit verbose
    dbxenv rtc_error_log_file_name errores.txt
    run 
  6. Al finalizar la ejecución del programa en caso de haber memory leaks veremos algo así:


  7. En el resultado de la ejecución podemos ver el call stack de la memoria que se esta perdiendo y asi poder corregir nuestro memory leak.
    Memory Leak (mel):
    Found leaked block of size 16 bytes at address 0x65658
    At time of allocation, the call stack was:
            [1] _alloc_result_header() (optimized), at 0xe75aad9c (line ~367) in "pin_decimal.c"
            [2] pin_decimal_set_scale() (optimized), at 0xe75ae960 (line ~3545) in "pin_decimal.c"
            [3] pin_decimal_from_double() (optimized), at 0xe75aca28 (line ~1719) in "pin_decimal.c"
            [4] pbo_decimal_from_double() (optimized), at 0xe75a8bd0 (line ~165) in "pbo_decimal.c"
            [5] pin_mta_worker_opcode() (optimized), at 0x15628 (line ~243) in "basic_mta.c"
    
  8. Ahí se ve el nombre del archivo(basic_mta.c) y la línea(243) donde esta el memory leak.
  9. Para ver el resto de los memory leaks hay que revisar el resto de los links en la solapa Memory leaks.

Makefile
OS=solaris
VERSION=7.5

##########

PINDIR=${PIN_HOME}
INCDIR=$(PINDIR)/include
LIBDIR=$(PINDIR)/lib

##########
CC_comp_solaris = cc
CC_link_solaris = CC
CC_comp_linux = gcc
CC_link_linux= gcc
CC_comp_hpux_ia64 = cc
CC_link_hpux_ia64 = $(CC_comp_hpux_ia64)
CC_comp_hpux = cc
CC_link_hpux = $(CC_comp_hpux)
CC_comp_aix = xlc_r
CC_link_aix = $(CC_comp_aix)
CC_comp = $(CC_comp_$(OS))
CC_link = $(CC_link_$(OS))

##########
CFLAGS_solaris= -g -xcg92 -O
CFLAGS_linux= -m32 -fPIC -g -pthread
CFLAGS_hpux_ia64= +Z
CFLAGS_hpux= -g -Ae +Z
CFLAGS_aix= -g -Drs6000 -Dunix -D__unix -D__aix
CFLAGS= $(CFLAGS_$(OS))

CPPFLAGS = -I$(INCDIR) 

LDFLAGS_solaris= -R:$(LIBDIR): 
LDFLAGS_linux= -m32 -Wl,--export-dynamic
LDFLAGS_hpux_ia64= -Wl,-E -Wl,+b:$(LIBDIR):
LDFLAGS_hpux= -Wl,-E -Wl,+b:$(LIBDIR):
LDFLAGS_aix=-bM:SRE -bexpall -brtl -lc
LDFLAGS = -L$(LIBDIR) $(LDFLAGS_$(OS))

OS_LIBS_solaris= -lsocket -lnsl -lgen -lposix4 -lpthread -ldl
OS_LIBS_hpux_ia64= -lsec -lrt -lpthread -lCsup -lunwind
OS_LIBS_hpux= -lsec -lrt -lpthread -lCsup
OS_LIBS_aix= -lpthread
OS_LIBS_linux= -lpthread

LDLIBS= -lportal -lmta -lpinsys $(OS_LIBS_$(OS))

##########

INCFILES= $(INCDIR)/pcm.h $(INCDIR)/pin_mta.h $(INCDIR)/pin_bill.h \
   $(INCDIR)/pin_cust.h $(INCDIR)/pin_act.h \
   $(INCDIR)/pin_errs.h $(INCDIR)/pinlog.h

###########

APPS= basic_mta

FILES= basic_mta.c

OBJECTS= basic_mta.o

DEP_linux=$(FILES)
DEP=$(DEP_$(OS))

###########

all: $(APPS) 

clean:
 rm -f $(OBJECTS) core

clobber: clean
 rm -f $(APPS)
 
###########

$(APPS): $(OBJECTS) $(INCFILES) Makefile
 $(CC_link) -o $@ $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(OBJECTS) $(LDLIBS)

$(OBJECTS): $(INCFILES) Makefile $(DEP)
 $(CC_comp) -c $(CFLAGS) $(CPPFLAGS) $(FILES)

###########

FRC:


basic_mta.c
#include <stdio.h>
#include <time.h>
#include "pcm.h"
#include "pin_errs.h"
#include "pinlog.h"
#include "pin_pymt.h"
#include "pin_mta.h"

/*******************************************************************
 * Configuration of application
 * Called prior MTA_CONFIG policy opcode
 *******************************************************************/
PIN_EXPORT void 
pin_mta_config(
 pin_flist_t  *param_flistp,
 pin_flist_t  *app_flistp,
 pin_errbuf_t *ebufp)
{
 int32   mta_flags = 0;
 void   *vp = NULL;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_config parameters flist", param_flistp);
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_config application info flist", app_flistp);
 
 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_FLAGS, 0,ebufp);
 if(vp)
  mta_flags = *((int32*)vp);

 /***********************************************************
 * The new flag MTA_FLAG_VERSION_NEW has been introduced to
 * differentiate between new mta & old mta applications as
 * only new applications have the ability to drop PIN_FLD_PARAMS
 * for valid parameters . It is only for new apps that
 * checking err_params_cnt is valid, otherwise for old applications
 * this check without a distincion for new applications would hamper
 * normal functioning.
 ***********************************************************/
 mta_flags = mta_flags | MTA_FLAG_VERSION_NEW;
 mta_flags = mta_flags | MTA_FLAG_BATCH_MODE;
 
 PIN_FLIST_FLD_SET (app_flistp, PIN_FLD_FLAGS, &mta_flags, ebufp);
 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_config error", ebufp);
 }
}

/*******************************************************************
* Usage information for the specific app.
* Called prior MTA_USAGE policy opcode
*******************************************************************/
PIN_EXPORT void
 pin_mta_usage(
 char *prog)
{
 pin_errbuf_t ebuf;
 pin_flist_t  *ext_flistp = NULL;
 char   *usage_str = NULL;
 char   *format = "\nModo de uso:\t %s\n";
 

 PIN_ERRBUF_CLEAR (&ebuf);
 
 usage_str = (char*)pin_malloc( strlen(format) + strlen(prog) + 1 );

 if (usage_str == NULL) {
  PIN_ERR_LOG_MSG(PIN_ERR_LEVEL_ERROR,"No Memory error");
  return;
 }

 sprintf(usage_str, format ,prog);

 ext_flistp = pin_mta_global_flist_node_get_no_lock(PIN_FLD_EXTENDED_INFO, &ebuf);

 PIN_FLIST_FLD_SET (ext_flistp, PIN_FLD_DESCR, usage_str, &ebuf);
 printf("%s \n", usage_str);
 if (PIN_ERR_IS_ERR(&ebuf)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_usage error", &ebuf);
 }
 
 pin_free(usage_str);
}

/*******************************************************************
 * Application defined search criteria.
 * Called prior MTA_INIT_SEARCH policy opcode
 *******************************************************************/
PIN_EXPORT void
pin_mta_init_search(
 pin_flist_t  *app_flistp,
 pin_flist_t  **s_flistpp,
 pin_errbuf_t *ebufp)
{
 pin_flist_t  *s_flistp = NULL;
 char            *template = "select x from /account where F1 in ('ROOT') ";
 int32   search_flag = 768;
 poid_t   *poid = NULL;
 void   *vp = NULL;
 pin_flist_t  *tmp_flistp = NULL;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_init_search application info flist", app_flistp);

 s_flistp = PIN_FLIST_CREATE(ebufp);
 poid = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_POID_VAL, 0, ebufp);
 PIN_FLIST_FLD_PUT(s_flistp, PIN_FLD_POID, PIN_POID_CREATE(PIN_POID_GET_DB(poid), "/search/pin", -1, ebufp), ebufp);
 PIN_FLIST_FLD_SET (s_flistp, PIN_FLD_FLAGS, &search_flag, ebufp);
 PIN_FLIST_FLD_SET (s_flistp, PIN_FLD_TEMPLATE, template, ebufp);
 tmp_flistp = PIN_FLIST_ELEM_ADD (s_flistp, PIN_FLD_ARGS, 1, ebufp);
 PIN_FLIST_FLD_SET (tmp_flistp, PIN_FLD_ACCOUNT_NO, "", ebufp);

 tmp_flistp = PIN_FLIST_ELEM_ADD (s_flistp, PIN_FLD_RESULTS, 0, ebufp);
 PIN_FLIST_FLD_SET (tmp_flistp, PIN_FLD_ACCOUNT_NO, "", ebufp);

 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_init_search error", ebufp);
  PIN_FLIST_DESTROY_EX (&s_flistp, NULL);
 }else{
  *s_flistpp = s_flistp;
  PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_init_search search flist", s_flistp);
 }
}

/*******************************************************************
 * Search results may be updated, modified or enriched
 * Called prior MTA_TUNE policy opcode
 *******************************************************************/
PIN_EXPORT void 
pin_mta_tune(
 pin_flist_t  *app_flistp,
 pin_flist_t  *srch_res_flistp,
 pin_errbuf_t *ebufp)
{
 pin_const_poid_type_t  type = 0;
 pin_cookie_t    s_cookie = 0;
 pin_cookie_t    m_cookie = 0;
 pin_flist_t     *multi_res_flistp = NULL;
 pin_flist_t     *tmp_flistp = NULL;
 poid_t      *pdp = 0;
 poid_t      *n_pdp = 0;
 int64      db = 0;
 int64      id = 0;
 int32      i = 0;
 int32      s_rec_id = 0;
 int32      m_rec_id = 0;
 void      *vp = 0;

 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }

 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "basic_mta application info flist", app_flistp);
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "basic_mta search results flist", srch_res_flistp);

 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_OPS_ERROR, MTA_OPTIONAL, ebufp);
 if(vp){
  i = *((int32*)vp);
 }
 
 if (i) {
  while((multi_res_flistp = PIN_FLIST_ELEM_GET_NEXT(srch_res_flistp, PIN_FLD_MULTI_RESULTS, &s_rec_id, 1, &s_cookie, ebufp)) != NULL) {
   m_cookie = 0;
   while((tmp_flistp = PIN_FLIST_ELEM_GET_NEXT(multi_res_flistp, PIN_FLD_RESULTS, &m_rec_id, 1, &m_cookie, ebufp)) != NULL) {
    vp = PIN_FLIST_FLD_TAKE (tmp_flistp, PIN_FLD_POID, 0, ebufp);
    if(vp) {
     pdp = (poid_t*)vp;
     db = PIN_POID_GET_DB (pdp);
     id = PIN_POID_GET_ID (pdp);
     type = PIN_POID_GET_TYPE (pdp);
     id = id * i;
     n_pdp = PIN_POID_CREATE (db, type,id, ebufp);
     PIN_POID_DESTROY (pdp, ebufp);
     PIN_FLIST_FLD_PUT (tmp_flistp, PIN_FLD_POID, n_pdp, ebufp);
    }
   }
  }
 }

 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_tune error", ebufp);
 }
}



/*******************************************************************
 * Function executed at application exit
 * Called prior MTA_EXIT policy opcode
 *******************************************************************/
PIN_EXPORT void
 pin_mta_exit(
 pin_flist_t  *app_flistp,
 pin_errbuf_t *ebufp)
{
 PIN_ERR_LOG_FLIST (PIN_ERR_LEVEL_DEBUG, "pin_mta_exit application info flist", app_flistp);
 if (PIN_ERR_IS_ERR(ebufp)) {
  PIN_ERR_LOG_EBUF(PIN_ERR_LEVEL_ERROR, "pin_mta_exit error", ebufp);
  printf("Error durante la ejecucion.\n");
 } else {
  printf("Ejecucion exitosa.\n");
 }
}

/*******************************************************************
 * Main application opcode is called here
 *******************************************************************/
PIN_EXPORT void 
pin_mta_worker_opcode(
 pcm_context_t *ctxp,
 pin_flist_t  *srch_res_flistp,
 pin_flist_t  *op_in_flistp,
 pin_flist_t  **op_out_flistpp,
 pin_flist_t  *ti_flistp,
 pin_errbuf_t *ebufp)
{
 pin_cookie_t cookie = NULL;
 pin_flist_t  *app_flistp = NULL;
 int32   rec_id = 0; 
 int32   mta_flags = 0;
 void   *vp = NULL;
 
 if (PIN_ERR_IS_ERR(ebufp)) {
  return;
 }
 
 app_flistp = pin_mta_global_flist_node_get_with_lock (PIN_FLD_APPLICATION_INFO, ebufp);

 vp = PIN_FLIST_FLD_GET (app_flistp, PIN_FLD_FLAGS, 0,ebufp);
 if(vp){
  mta_flags = *((int32*)vp);
 }
 
 pin_mta_global_flist_node_release(PIN_FLD_APPLICATION_INFO, ebufp);
 
 //memory leak agregado a proposito
 pin_decimal_t *amount = pbo_decimal_from_double(90, ebufp);
 
 //memory leak agregado a proposito
 poid_t *poid = PIN_POID_CREATE(1, "/account", -1, ebufp);
 
 //memory leak agregado a proposito
 pin_flist_t *tmp_flistp = PIN_FLIST_COPY(op_in_flistp, ebufp);

 //memory leak agregado a proposito
 char *str = (char*)malloc(sizeof(char));
} 
 
 
Martín Falconi

No hay comentarios.:

Publicar un comentario