My crash issue stems from   iinfo->free_data_context cb being called 
repeatedly with the same address to free. Any thoughts?
thanksIan

   ----- Forwarded Message ----- From: Ian C via Net-snmp-coders 
<net-snmp-coders@lists.sourceforge.net>To: 
net-snmp-coders@lists.sourceforge.net 
<net-snmp-coders@lists.sourceforge.net>Sent: Tuesday, August 25, 2020, 3:20:07 
p.m. EDTSubject: Table Iterator Crashes in free_data_context
 
I'm still having a crash issue with my table agent, I can't figure out a 
solution, hoping the list members could help. In a nutshell I want to read a 
QNX pps object (file) each time (no caching) it is queried (snmpwalk). The data 
gets read and returned but a crash happens on the free (datactx).
I would really appreciate a hand.
thanks,Ian  

Net-Snmp 5.9QNX 7.1
/* * Note: this file originally auto-generated by mib2c using
 *  : mib2c.iterate.conf 19302 2010-08-13 12:19:42Z dts12 $
 */
/* generated from net-snmp-config */
extern "C" {
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "chAsinHwSbcNtpTable.h"
#include <syslog.h>
#include <string.h>
}


void populateLocalSNMPstruct( struct chAsinHwSbcNtpTable_entry **table, const 
char channel );


/** Initializes the chAsinHwSbcNtpTable module */
extern "C" void
init_chAsinHwSbcNtpTable(void)
{
  /* here we initialize all the tables we're planning on supporting */
    //syslog( LOG_DEBUG, "init_chAsinHwSbcNtpTable()");
    initialize_table_chAsinHwSbcNtpTable();
}

//  # Determine the first/last column names


void
nsModuleTable_loop_free(void *context, netsnmp_iterator_info *dont_care)
{
    free(context);
}


void freeTableEntry( void *data_context, netsnmp_iterator_info *useless ) {
      if (data_context != NULL) {
          free(data_context); <<<<<<<==== CRASHES HERE ON 1st CALL
      }
    return;
}

/** Initialize the chAsinHwSbcNtpTable table by defining its contents and how 
it's structured */
void
initialize_table_chAsinHwSbcNtpTable(void)
{
    //syslog( LOG_ERR, "initialize_table_chAsinHwSbcNtpTable()");
    const oid chAsinHwSbcNtpTable_oid[] = {1,3,6,1,4,1,12345,3,3,1,9,6,6}; // 
12345 is fictitious
    const size_t chAsinHwSbcNtpTable_oid_len   = 
OID_LENGTH(chAsinHwSbcNtpTable_oid);
    netsnmp_handler_registration    *reg;
    netsnmp_iterator_info           *iinfo;
    netsnmp_table_registration_info *table_info;

    DEBUGMSGTL(("chAsinHwSbcNtpTable:init", "initializing table 
chAsinHwSbcNtpTable\n"));

    reg = netsnmp_create_handler_registration(
              "chAsinHwSbcNtpTable",     chAsinHwSbcNtpTable_handler,
              chAsinHwSbcNtpTable_oid, chAsinHwSbcNtpTable_oid_len,
              HANDLER_CAN_RONLY
              );

    table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info );
    netsnmp_table_helper_add_indexes(table_info,
                           ASN_OCTET_STR,  /* index: chAsinHwSbcNtpSbcName */
                           0);
    table_info->min_column = COLUMN_CHASINHWSBCNTPSBCNAME;
    table_info->max_column = COLUMN_CHASINHWSBCNTPSTATUSSTRING;
    
    iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info );
    iinfo->get_first_data_point = chAsinHwSbcNtpTable_get_first_data_point;
    iinfo->get_next_data_point  = chAsinHwSbcNtpTable_get_next_data_point;
    iinfo->table_reginfo        = table_info;
    iinfo->free_loop_context_at_end = nsModuleTable_loop_free;
    iinfo->free_data_context = freeTableEntry; // <<<<<<==== MEM LEAK WITHOUT 
THIS! 

    netsnmp_register_table_iterator( reg, iinfo );

    /* Initialise the contents of the table here */
}

struct chAsinHwSbcNtpTable_entry  *chAsinHwSbcNtpTable_head;

/* create a new row in the (unsorted) table */
struct chAsinHwSbcNtpTable_entry *
chAsinHwSbcNtpTable_createEntry(
                 char* chAsinHwSbcNtpSbcName,
                 size_t chAsinHwSbcNtpSbcName_len
                ) {
    struct chAsinHwSbcNtpTable_entry *entry;

    entry = SNMP_MALLOC_TYPEDEF(struct chAsinHwSbcNtpTable_entry);
    if (!entry)
        return NULL;

    memcpy(entry->chAsinHwSbcNtpSbcName, chAsinHwSbcNtpSbcName, 
chAsinHwSbcNtpSbcName_len);
    entry->chAsinHwSbcNtpSbcName_len = chAsinHwSbcNtpSbcName_len;
    entry->next = chAsinHwSbcNtpTable_head;
    chAsinHwSbcNtpTable_head = entry;
    return entry;
}

/* remove a row from the table */
void
chAsinHwSbcNtpTable_removeEntry( struct chAsinHwSbcNtpTable_entry *entry ) {
    struct chAsinHwSbcNtpTable_entry *ptr, *prev;

    if (!entry)
        return;    /* Nothing to remove */

    for ( ptr  = chAsinHwSbcNtpTable_head, prev = NULL;
          ptr != NULL;
          prev = ptr, ptr = ptr->next ) {
        if ( ptr == entry )
            break;
    }
    if ( !ptr )
        return;    /* Can't find it */

    if ( prev == NULL )
        chAsinHwSbcNtpTable_head = ptr->next;
    else
        prev->next = ptr->next;

    SNMP_FREE( entry );   /* XXX - release any other internal resources */
}


/* Example iterator hook routines - using 'get_next' to do most of the work */
netsnmp_variable_list *
chAsinHwSbcNtpTable_get_first_data_point(void **my_loop_context,
                          void **my_data_context,
                          netsnmp_variable_list *put_index_data,
                          netsnmp_iterator_info *mydata)
{
    populateLocalSNMPstruct( &chAsinHwSbcNtpTable_head, 'A' ); // collect NTP 
data for channel 'A'
    *my_loop_context = chAsinHwSbcNtpTable_head;
    return chAsinHwSbcNtpTable_get_next_data_point(my_loop_context, 
my_data_context,
                                    put_index_data,  mydata );
}

netsnmp_variable_list *
chAsinHwSbcNtpTable_get_next_data_point(void **my_loop_context,
                          void **my_data_context,
                          netsnmp_variable_list *put_index_data,
                          netsnmp_iterator_info *mydata)
{
    struct chAsinHwSbcNtpTable_entry *entry = (struct chAsinHwSbcNtpTable_entry 
*)*my_loop_context;
    netsnmp_variable_list *idx = put_index_data;

    if ( entry ) {
        snmp_set_var_value( idx, entry->chAsinHwSbcNtpSbcName, 
sizeof(entry->chAsinHwSbcNtpSbcName) );
        idx = idx->next_variable;
        *my_data_context = (void *)entry;
        *my_loop_context = (void *)entry->next;
        return put_index_data;
    } else {
        return NULL;
    }
}


/** handles requests for the chAsinHwSbcNtpTable table */
int
chAsinHwSbcNtpTable_handler(
    netsnmp_mib_handler               *handler,
    netsnmp_handler_registration      *reginfo,
    netsnmp_agent_request_info        *reqinfo,
    netsnmp_request_info              *requests) {

    netsnmp_request_info       *request;
    netsnmp_table_request_info *table_info;
    struct chAsinHwSbcNtpTable_entry          *table_entry;

    DEBUGMSGTL(("chAsinHwSbcNtpTable:handler", "Processing request (%d)\n", 
reqinfo->mode));

    switch (reqinfo->mode) {
        /*
         * Read-support (also covers GetNext requests)
         */
    case MODE_GET:
        for (request=requests; request; request=request->next) {
            table_entry = (struct chAsinHwSbcNtpTable_entry *)
                              netsnmp_extract_iterator_context(request);
            table_info  =     netsnmp_extract_table_info(      request);
    
            switch (table_info->colnum) {
            case COLUMN_CHASINHWSBCNTPSBCNAME:
                if ( !table_entry ) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
                snmp_set_var_typed_value( request->requestvb, ASN_OCTET_STR,
                                          table_entry->chAsinHwSbcNtpSbcName,
                                          
table_entry->chAsinHwSbcNtpSbcName_len);
                break;
            case COLUMN_CHASINHWSBCNTPSTATUSSTRING:
                if ( !table_entry ) {
                    netsnmp_set_request_error(reqinfo, request,
                                              SNMP_NOSUCHINSTANCE);
                    continue;
                }
                snmp_set_var_typed_value( request->requestvb, ASN_OCTET_STR,
                                          
table_entry->chAsinHwSbcNtpStatusString,
                                          
table_entry->chAsinHwSbcNtpStatusString_len);
                break;
            default:
                netsnmp_set_request_error(reqinfo, request,
                                          SNMP_NOSUCHOBJECT);
                break;
            }
        }
        break;

    }
    return SNMP_ERR_NOERROR;
}





// 
====================================================================================================
// Populate the given Net-Snmp-generated struct with PPS data, in this case we 
want all /pps/ntp
// data from all SBCs of the given channel.
//
void populateLocalSNMPstruct( struct chAsinHwSbcNtpTable_entry **table, const 
char channel )
{
    std::list< fpair_type > allSbcNtps;  // full path, sbc name
    // For testing/dev only one file to read...
    allSbcNtps.push_back( std::make_pair( "/pps/ntp", "A1" )); // pps is 
QNX-specific, think of it as a file

    // process the list of paths extracting the json formatted ntp data
    struct chAsinHwSbcNtpTable_entry * tail, * head;
    head = NULL;
    tail = NULL;

    BOOST_FOREACH( const fpair_type & s, allSbcNtps ) {

        // open, read and close pps object
        char ppsData[2000];
        readFile( s.first.c_str(), ppsData, sizeof( ppsData )); // readFile 
reads entire pps/file in one shot (impl not included here)

        std::string json( ppsData );
        // get rid of all lines before json line (which starts with "sources:"
        size_t pos;
        if( std::string::npos != ( pos = json.find("sources:"))) {
            json.erase( 0, pos );
        }
        // get rid of all lines after the json line (which ends with "}]}"
        if( std::string::npos != ( pos = json.find("}]}"))) {
            json.erase( pos + strlen("}]}") );
        }

        // at this point ppsData is of the form "sources:json:{"data":[{...}]}
        // the 'sources:json:' isn't actually part of our json data, it's the 
way QNX PPS objects identify json data, so strip it away
        json.erase( 0, strlen("sources:json:"));

        struct chAsinHwSbcNtpTable_entry * current;
        current = reinterpret_cast< chAsinHwSbcNtpTable_entry *>( 
SNMP_MALLOC_TYPEDEF( struct chAsinHwSbcNtpTable_entry ));
        strncpy( current->chAsinHwSbcNtpStatusString, json.c_str(), JSONSIZE );
        current->chAsinHwSbcNtpStatusString_len = json.size();
        strncpy( current->chAsinHwSbcNtpSbcName, s.second.c_str(), NAMESIZE );
        current->chAsinHwSbcNtpSbcName_len = s.second.size();
        current->next = NULL;

        if( head == NULL ) {
            head = current;
        }
        else {
            tail->next = current;
        }
        tail = current;
    }
    *table = head;
}


_______________________________________________
Net-snmp-coders mailing list
Net-snmp-coders@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders
  
_______________________________________________
Net-snmp-coders mailing list
Net-snmp-coders@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/net-snmp-coders

Reply via email to