memory allocation of `getaddrinfo()` - memory

I have a simple program which calls getaddrinfo() and freeaddrinfo().
I run valgrind on it, and it shows that there is no memory leak.
in use at exit: 0 bytes in 0 blocks
total heap usage: 108 allocs, 109 frees
However, I wrote a memory debugger named memleax which attaches the target process and traps at malloc() and free() to detect memory leak. I use memleax to detect the getaddrinfo() program, and it catches free() only 43 times.
Then I hook the malloc() and free() by malloc-hooks,
and it also shows free() only 43 times.
So my question is that, what is the difference between valgrind and hooking-malloc?
Original code:
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
int main()
{
struct addrinfo *aihead;
sleep(4);
printf(" --- getaddrinfo ---\n");
int error = getaddrinfo("dig.chouti.com", "http", NULL, &aihead);
if(error) {
printf("error: %s\n", gai_strerror(error));
return error;
}
sleep(4);
printf("\n\n\n --- freeaddrinfo ---\n");
freeaddrinfo(aihead);
sleep(4);
return 0;
}
Code with malloc-hook
#include <sys/types.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
/* Prototypes for __malloc_hook, __free_hook */
#include <malloc.h>
/* Prototypes for our hooks. */
static void my_init_hook (void);
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
static void *(*old_malloc_hook) (size_t, const void *);
static void (*old_free_hook) (void*, const void *);
static void
my_init (void)
{
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
static void *
my_malloc_hook (size_t size, const void *caller)
{
void *result;
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
result = malloc (size);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call malloc, so protect it too. */
printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
return result;
}
static void
my_free_hook (void *ptr, const void *caller)
{
/* Restore all old hooks */
__malloc_hook = old_malloc_hook;
__free_hook = old_free_hook;
/* Call recursively */
free (ptr);
/* Save underlying hooks */
old_malloc_hook = __malloc_hook;
old_free_hook = __free_hook;
/* printf might call free, so protect it too. */
printf ("freed pointer %p\n", ptr);
/* Restore our own hooks */
__malloc_hook = my_malloc_hook;
__free_hook = my_free_hook;
}
int main()
{
my_init();
struct addrinfo *aihead;
printf(" --- getaddrinfo ---\n");
int error = getaddrinfo("dig.chouti.com", "http", NULL, &aihead);
if(error) {
printf("error: %s\n", gai_strerror(error));
return error;
}
sleep(4);
printf("\n\n\n --- freeaddrinfo ---\n");
freeaddrinfo(aihead);
sleep(4);
return 0;
}

I find this in valgrind's output:
--13197-- Discarding syms at 0x55f9240-0x5600454 in /usr/lib64/libnss_files-2.17.so due to mu
--13197-- Discarding syms at 0x580b100-0x580e590 in /usr/lib64/libnss_dns-2.17.so due to munm
--13197-- Discarding syms at 0x5a13a40-0x5a22854 in /usr/lib64/libresolv-2.17.so due to munma
==13197== Invalid free() / delete / delete[] / realloc()
==13197== at 0x4C2AD17: free (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==13197== by 0x4F9963B: __libc_freeres (in /usr/lib64/libc-2.17.so)
==13197== by 0x4A246B4: _vgnU_freeres (in /usr/lib64/valgrind/vgpreload_core-amd64-linux.s
==13197== by 0x4E6DE2A: __run_exit_handlers (in /usr/lib64/libc-2.17.so)
==13197== by 0x4E6DEB4: exit (in /usr/lib64/libc-2.17.so)
==13197== by 0x4E56B1B: (below main) (in /usr/lib64/libc-2.17.so)
==13197== Address 0x51f03d0 is 0 bytes inside data symbol "noai6ai_cached"
It seems that libc-nss frees some memory at __run_exit_handlers() after exit().
So maybe valgrid keeps tracing memory after target process's exit(). While malloc-hook stops working after exit().

Related

Pthreads based program crashing on MacOS doesn't crash on Linux

I have a pthreads based program with 3 threads that crashes on MacOS (Darwin Kernel Version 19.6.0) within a few seconds. I was expecting the same behavior on Linux. But the program doesn't crash on Linux. I am left speculating if Linux has a different thread scheduling policy or if it is something else. Any pointers appreciated.
This is the program. If I don't use pthread mutex lock in the printer thread, it is supposed to crash because the linked list is left in an inconsistent state.
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
#include "list.h"
#define RANGE_MIN 1
#define RANGE_MAX 10
pthread_t tid[3];
list_t list;
pthread_mutex_t queue_lock;
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand() / (RAND_MAX + 1.0));
}
/*
* consumer thread function
*/
void* consumer(void *arg)
{
static int val = 0;
while (1) {
//sleep(1);
pthread_mutex_lock(&queue_lock);
while (list.total_elem > 0)
consume_and_delete(&list);
pthread_mutex_unlock(&queue_lock);
}
}
void *producer(void *arg)
{
while (1) {
//sleep(1);
pthread_mutex_lock(&queue_lock);
while (list.total_elem < 10)
add_to_list(&list, random_range(RANGE_MIN, RANGE_MAX));
pthread_mutex_unlock(&queue_lock);
}
}
/*
* printer thread function
*/
void* printer(void *arg)
{
while (1) {
//pthread_mutex_lock(&queue_lock); //lines deliberately commented out to show the crash
print_list(&list);
//pthread_mutex_unlock(&queue_lock);
}
}
int main(void)
{
int ret;
if (pthread_mutex_init(&queue_lock, NULL) != 0) {
printf("\n mutex init failed\n");
return 1;
}
ret = pthread_create(&(tid[1]), NULL, &consumer, NULL);
if (ret != 0) {
printf("\ncan't create thread :[%s]", strerror(ret));
}
ret = pthread_create(&(tid[0]), NULL, &producer, NULL);
if (ret != 0) {
printf("\ncan't create thread :[%s]", strerror(ret));
}
ret = pthread_create(&(tid[2]), NULL, &printer, NULL);
if (ret != 0) {
printf("\ncan't create thread :[%s]", strerror(ret));
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_join(tid[2], NULL);
pthread_mutex_destroy(&queue_lock);
return 0;
}
For the sake of completeness, here is the code for list.h and list.c
ifndef __LIST_H__
#define __LIST_H__
typedef struct node_ {
int num;
struct node_ *next;
} node_t;
typedef struct list_ {
int total_elem;
node_t *head;
} list_t;
#define TRUE 1
#define FALSE 0
void add_to_list(list_t *list, int num);
node_t *allocate_new(int num);
void consume_and_delete(list_t *list);
void print_list(list_t *list);
#endif
list.c:
#include <stdio.h>
#include <stdlib.h>
#include "list.h"
void add_to_list(list_t *list, int val)
{
node_t *tmp;
node_t *new;
new = allocate_new(val);
if (!new) {
printf("%s: allocation failure \n", __FUNCTION__);
}
printf("%s: Enqueueing %d\n", __FUNCTION__, new->num);
if (!list) {
return;
}
if (!list->head) {
list->total_elem++;
list->head = new;
return;
}
tmp = list->head;
while (tmp->next) {
tmp = tmp->next;
}
tmp->next = new;
list->total_elem++;
}
node_t *allocate_new(int num)
{
node_t *tmp;
tmp = malloc(sizeof(node_t));
if (!tmp) {
printf("%s: failed in malloc\n", __FUNCTION__);
return NULL;
}
tmp->num = num;
tmp->next = NULL;
return tmp;
}
/* reads from the front of the queue and deletes the element
*/
void consume_and_delete(list_t *list)
{
node_t *tmp, *next;
if (!list->head) {
return;
}
tmp = list->head;
next = tmp->next;
printf("%s: Dequeueing %d\n", __FUNCTION__,tmp->num);
list->head = next;
list->total_elem--;
free(tmp);
}
void print_list(list_t *list)
{
node_t *tmp;
if (!list->head) {
printf("%s: queue empty \n", __FUNCTION__);
}
tmp = list->head;
while (tmp) {
printf("%d ", tmp->num);
tmp = tmp->next;
}
printf("\n");
}
Makefile:
all: prodcon
prodcon: list.o prod_consume.o
gcc -g -o prodcon list.o prod_consume.o -lpthread
list.o: list.c list.h
gcc -g -c -o list.o list.c
prod_consume.o: prod_consume.c list.h
gcc -g -c -o prod_consume.o prod_consume.c
clean:
rm -f *.o ./prodcon
Note that if I un-comment pthread_mutex_lock and unlock calls in printer fn, the program runs without a crash on MacOS, as expected. But on Linux, even without un-commenting those lines in printer thread, it runs fine.
So my question. Is thread scheduling different in Linux. Or is is there some other reason?
Any reason the program runs fine on Linux, while it crahes on MacOS?
//lines deliberately commented out to show the crash
The print_list accesses the list without the lock; of course the code will intermittently crash, what did you expect?
on Linux, even without un-commenting those lines in printer thread, it runs fine.
It doesn't "run fine" -- it exercises undefined behavior, and will crash if you run enough times and the stars align to expose the data race.

How to get memory rd/wr trace for a specific function call using PIN tools

I am trying to dump mem rd/wr trace for a specific function call from my application and after researching a bit I came across a solution to do so.
But since I am very new to PIN usage, I am not sure how to pass routine names (refer to Routine(RTN rtn, VOID *v)) from application to pin tools so that the right callback function gets trigerred. Can someone please help?
As of now If I run the given pin tools, my trace.out is empty because "!isROI" is always set to false.
#include <stdio.h>
#include "pin.H"
#include <string>
const CHAR * ROI_BEGIN = "__parsec_roi_begin";
const CHAR * ROI_END = "__parsec_roi_end";
FILE * trace;
bool isROI = false;
// Print a memory read record
VOID RecordMemRead(VOID * ip, VOID * addr, CHAR * rtn)
{
// Return if not in ROI
if(!isROI)
{
return;
}
// Log memory access in CSV
fprintf(trace,"%p,R,%p,%s\n", ip, addr, rtn);
}
// Print a memory write record
VOID RecordMemWrite(VOID * ip, VOID * addr, CHAR * rtn)
{
// Return if not in ROI
if(!isROI)
{
return;
}
// Log memory access in CSV
fprintf(trace,"%p,W,%p,%s\n", ip, addr, rtn);
}
// Set ROI flag
VOID StartROI()
{
isROI = true;
}
// Set ROI flag
VOID StopROI()
{
isROI = false;
}
// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v)
{
// Instruments memory accesses using a predicated call, i.e.
// the instrumentation is called iff the instruction will actually be executed.
//
// On the IA-32 and Intel(R) 64 architectures conditional moves and REP
// prefixed instructions appear as predicated instructions in Pin.
UINT32 memOperands = INS_MemoryOperandCount(ins);
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < memOperands; memOp++)
{
// Get routine name if valid
const CHAR * name = "invalid";
if(RTN_Valid(INS_Rtn(ins)))
{
name = RTN_Name(INS_Rtn(ins)).c_str();
}
if (INS_MemoryOperandIsRead(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemRead,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_ADDRINT, name,
IARG_END);
}
// Note that in some architectures a single memory operand can be
// both read and written (for instance incl (%eax) on IA-32)
// In that case we instrument it once for read and once for write.
if (INS_MemoryOperandIsWritten(ins, memOp))
{
INS_InsertPredicatedCall(
ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp,
IARG_ADDRINT, name,
IARG_END);
}
}
}
// Pin calls this function every time a new rtn is executed
VOID Routine(RTN rtn, VOID *v)
{
// Get routine name
const CHAR * name = RTN_Name(rtn).c_str();
if(strcmp(name,ROI_BEGIN) == 0) {
// Start tracing after ROI begin exec
RTN_Open(rtn);
RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)StartROI, IARG_END);
RTN_Close(rtn);
} else if (strcmp(name,ROI_END) == 0) {
// Stop tracing before ROI end exec
RTN_Open(rtn);
RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)StopROI, IARG_END);
RTN_Close(rtn);
}
}
// Pin calls this function at the end
VOID Fini(INT32 code, VOID *v)
{
fclose(trace);
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
PIN_ERROR( "This Pintool prints a trace of memory addresses\n"
+ KNOB_BASE::StringKnobSummary() + "\n");
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, char *argv[])
{
// Initialize symbol table code, needed for rtn instrumentation
PIN_InitSymbols();
// Usage
if (PIN_Init(argc, argv)) return Usage();
// Open trace file and write header
trace = fopen("roitrace.csv", "w");
fprintf(trace,"pc,rw,addr,rtn\n");
// Add instrument functions
RTN_AddInstrumentFunction(Routine, 0);
INS_AddInstrumentFunction(Instruction, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}

pthread error code 3025 (ENOENT) on the as400/IBM i?

When I have the following C source code, which is running on an IBM i Midrange, then I get a non-zero result from pthread_create, specifically 3025, which is ENOENT (No such path or directory), which doesn't make any sense to me. Anyone have any thoughts on what the error actually means in this context.
#define _MULTI_THREADED
#define _XOPEN_SOURCE 520
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
void* workerThread(void* parm) {
// Do some work here
pthread_exit(NULL);
}
int main(int argc, char* argv[]) {
pthread_t t;
int rc;
rc = pthread_create(&t, NULL, workerThread, NULL);
if (rc != 0) {
char *msg = strerror(errno);
perror("pthread_create failed");
}
// Other code here
return 0;
}
pthread_create doesn't set errno. You should be checking strerror of rc.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/pthread_create.html
char *msg = strerror(rc);

pthread_cond_timedwait not returning after specified timeout

In the following code execute_on_thread() will keep on printing ".",
while the main function waits for a condition to be signaled from execute_on_thread using pthread_cond_timedwait. However, it is not timing out after the specified 20 second timeout, it just keeps printing ".", nothing else is happening.
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define SHOW_TECH_CMD_MAX_EXEC_TIME 5 //in secs
pthread_mutex_t waitMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t waitCond = PTHREAD_COND_INITIALIZER;
void *execute_on_thread();
void *execute_on_thread()
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_mutex_lock( &waitMutex );
while(1)
{
printf(".");
}
pthread_cond_signal( &waitCond );
pthread_mutex_unlock( &waitMutex );
return (void *) 0;
}
int main( )
{
pthread_t tid;
struct timespec ts;
int error;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 20;
pthread_create(&tid,NULL,execute_on_thread,NULL);
pthread_mutex_lock(&waitMutex);
error = pthread_cond_timedwait(&waitCond, &waitMutex,&ts);
pthread_mutex_unlock(&waitMutex);
printf("come here 1\n");
if(error == ETIMEDOUT)
{
printf("come here 2\n");
error = pthread_cancel(tid);
if(error != 0)
{
printf("come here 3\n");
}
}
}
Have a look at the documentation for pthread_cond_wait:
Upon successful return, the mutex shall have been locked and shall be
owned by the calling thread.
So, before pthread_cond_wait returns, be it due to a signal arriving or timing out, it tries to lock the mutex. But - since execute_on_thread never releases the mutex once it has it (due to the while(1) loop), pthread_cond_wait will be stuck waiting on the mutex to be unlocked.
If you for instance change your execute_on_thread to temporarily unlock the mutex during each cycle, you should be able to get it to work. For instance:
void *execute_on_thread()
{
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //Not necessary - this is the default state for new threads
pthread_mutex_lock( &waitMutex );
while(1)
{
printf(".\n");
pthread_mutex_unlock(&waitMutex);
usleep(100*1000); //So that the screen doesn't completely fill up with '.'s
pthread_mutex_lock( &waitMutex );
}
pthread_cond_signal( &waitCond );
pthread_mutex_unlock( &waitMutex );
return (void *) 0;
}
Note though, that there are a couple of other things that could be improved in your program - such as adding a guard variable to your conditional wait (have a look at condition variable - why calling pthread_cond_signal() before calling pthread_cond_wait() is a logical error?), adding a cleanup handler to make sure the mutex is unlocked if the cancel request is handled by execute_on_thread when the mutex is locked and similar tweaks.

Capturing beacon frames in 802.11

How can I capture 802.11 beacon frames on my linux machine using a C program.Also how can I send a frame response using a C program?
Try using libpcap. See this answer on SO for a basic example.
below program only work :-
1. if your device support link layer type as DLT_IEEE802_11_RADIO
2. if you ahev libpacp installed in your machine.
3. compile it with libcap library( ex:- cc prog.c -lpcap
4. during run provide interface on command line ( ex:- a.out wlan0)
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void packet_view(unsigned char *args,const struct pcap_pkthdr *h,const unsigned char *p);
#define SNAP_LEN 3000
void packet_view(
unsigned char *args,
const struct pcap_pkthdr *h,
const unsigned char *p
){
int len;
len = 0;
printf("PACKET\n");
while(len < h->len) {
printf("%02x ", *(p++));
if(!(++len % 16))
printf("\n");
}
printf("\n");
return ;
}
int main(int argc, char **argv)
{
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "wlan type mgt subtype beacon"; /* filter expression [3] */
// char filter_exp[] = "ip"; /* filter expression [3] */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
/* check for capture device name on command-line */
if (argc == 2) {
dev = argv[1];
}
else if (argc > 2) {
fprintf(stderr, "error: unrecognized command-line options\n\n");
exit(EXIT_FAILURE);
}
else {
/* find a capture device if not specified on command-line */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n",
errbuf);
exit(EXIT_FAILURE);
}
}
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, -1, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* for Ethernet device change the type to DLT_EN10MB */
/* your wlan device need to supprot this link layer type otherwise failure */
if (pcap_datalink(handle) != DLT_IEEE802_11_RADIO) {
fprintf(stderr, "%s is not an Wlan packet\n", dev);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 1,PCAP_NETMASK_UNKNOWN) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* now we can set our callback function */
pcap_loop(handle, num_packets, packet_view, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
printf("\nCapture complete.\n");
return 0;
}

Resources