I face one issue in my customized malloc().
My software
First of all, let me explain my software:
My software is huge and is composed of multiple static libraries. As one of static libraries has the customized malloc(), whose main function is a sort of proprietary memory tracer on the top of calling mall() from glibc. Currently the customized malloc() is available only some applications but not all applications in my system. My aim is to link the customized malloc() to every application running on my system. In my previous post, I asked why there was 'undefined sysmbol' shown during the run time even though I used the flag of LTLD_LAZY. It turned out the my code was not correct. So I fixed my code. And the issue is resolved. But still I have an issue. Let me explain my code first.
cat common.c
#include <stdio.h>
#include <stdlib.h>
void *gp_malloc(size_t size) {
void *ptr;
ptr = malloc(size);
fprintf(stderr, "%s: size(%d) = %p\n", __func__, (int)size, ptr);
return ptr;
}
void gp_free(void *ptr) {
free(ptr);
fprintf(stderr, "%s free=%p\n", __func__, ptr);
}
cat my_malloc.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <malloc.h>
static void *handle = NULL;
static void *(*gp_malloc)(size_t size) = NULL;
static void (*gp_free)(void *ptr) = NULL;
void *my_malloc(size_t size) {
char *error;
void *ptr;
/* dynamically load the shared lib that contains gp_malloc() */
if (gp_malloc == NULL) {
handle = dlopen("./libcommon.so", RTLD_LAZY| RTLD_GLOBAL);
if (!handle) {
fprintf(stderr, "%s\n", dlerror());
return NULL;
}
/* get a pointer to the gp_malloc() function we just loaded */
gp_malloc = dlsym(handle, "gp_malloc");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return NULL;
}
}
/* Now we can call gp_malloc() just like any other function */
fprintf(stderr, "%s size=%ld\n", __func__, size);
ptr = gp_malloc(size);
return ptr;
}
void my_free(void *ptr) {
char *error;
//void *ptr;
/* dynamically load the shared lib that contains gp_malloc() */
if (gp_free == NULL) {
gp_free = dlsym(handle, "gp_malloc");
if ((error = dlerror()) != NULL) {
fprintf(stderr, "%s\n", error);
return;
}
}
/* Now we can call gp_malloc() just like any other function */
fprintf(stderr, "%s: start %p\n", __func__, ptr);
gp_free(ptr);
}
void bbb(void) {
extern void aaa(void);
aaa();
}
cat hello_exits.c
#include <stdio.h>
#include <stdlib.h>
extern void *gp_malloc(int);
extern void gp_free(void *);
int main(void) {
char *ptr;
ptr = gp_malloc(10);
gp_free(ptr);
exit(0);
}
cat hello_new.c
#include <stdio.h>
#include <stdlib.h>
#include "my_malloc.h"
int main(void) {
char *ptr;
ptr = malloc(10);
free(ptr);
}
cat my_static.c
#include <stdio.h>
void aaa(void) {
printf("I am in aaa\n");
}
cat my_malloc.h
#ifdef COMPILE_TIME_MY_MALLOC
#define malloc(size) my_malloc(size)
#define free(ptr) my_free(ptr)
void *my_malloc(size_t size);
void my_free(void *ptr);
#endif
cat Makefile_new
LOCAL_PATH=${shell pwd}
all:
gcc -c -Wall -fPIC -o my_malloc.o -c my_malloc.c
gcc -O2 -Wall -shared -fPIC -o libmy_malloc.so my_malloc.o
# This shared library is built with Makefile_exist
# gcc -O2 -Wall -shared -fPIC -o libcommon.so common.c
gcc -L${LOCAL_PATH} -g -Wall -D COMPILE_TIME_MY_MALLOC -o hello_new hello_new.c -lmy_malloc -ldl
cat Makefile_exist
LOCAL_PATH=${shell pwd}
all:
gcc -c -Wall -o my_static.o -c my_static.c
ar -rc libmy_static.a my_static.o
gcc -O2 -Wall -shared -fPIC -o libcommon.so common.c
gcc -L${LOCAL_PATH} -g -Wall -o hello_exist hello_exist.c -lcommon -lmy_static -ldl
In order to build the image, run Makefile_exist, Makefile_new sequentially so that hello_new is created. (Makefile_exist/Makefile_new is a simplified version of my makefiles. The former is one that I use. The later is one that I am going to apply to other applications)
When I run hello_new, I got gp_malloc twice. I understand the 1st one. What causes the 2nd gp_malloc()?
./hello_new
my_malloc size=10
gp_malloc: size(10) = 0x7fffe0d5b900
my_free: start 0x7fffe0d5b900
gp_malloc: size(-522864384) = (nil) //what causes this to be called.
Any suggestion will be highly appreciated.
Related
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.
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);
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().
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;
}
I got the D-Bus server.c and client.c code, and made some modification.
I want the result that when type for example "hi" from client.c
server will print "receive message hi", and reply "reply_content!!!!!!" to client.c
But it seems that now client.c cannot get the reply message.
Anyone have the idea?
Thanks in advance.
"server.c"
/* server.c */
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static DBusHandlerResult
filter_func(DBusConnection *connection, DBusMessage *message, void *usr_data)
{
DBusMessage *reply;
dbus_bool_t handled = false;
char *word = NULL;
DBusError dberr;
dbus_error_init(&dberr);
dbus_message_get_args(message, &dberr, DBUS_TYPE_STRING, &word, DBUS_TYPE_INVALID);
printf("receive message: %s\n", word);
handled = true;
reply = dbus_message_new_method_return(message);
char * reply_content = "reply_content!!!!!!";
dbus_message_append_args(reply, DBUS_TYPE_STRING, &reply_content, DBUS_TYPE_INVALID);
dbus_connection_send(connection, reply, NULL);
dbus_connection_flush(connection);
dbus_message_unref(reply);
return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
}
int main(int argc, char *argv[])
{
DBusError dberr;
DBusConnection *dbconn;
dbus_error_init(&dberr);
dbconn = dbus_bus_get(DBUS_BUS_SESSION, &dberr);
if (!dbus_connection_add_filter(dbconn, filter_func, NULL, NULL)) {
return -1;
}
dbus_bus_add_match(dbconn, "type='signal',interface='client.signal.Type'", &dberr);
while(dbus_connection_read_write_dispatch(dbconn, -1)) {
/* loop */
}
return 0;
}
Here is client.c
#include <dbus/dbus.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static DBusHandlerResult
filter_func(DBusConnection *connection, DBusMessage *message, void *usr_data)
{
dbus_bool_t handled = false;
char *word = NULL;
DBusError dberr;
dbus_error_init(&dberr);
dbus_message_get_args(message, &dberr, DBUS_TYPE_STRING, &word, DBUS_TYPE_INVALID);
printf("receive message %s\n", word);
handled = true;
return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
}
int db_send(DBusConnection *dbconn)
{
DBusMessage *dbmsg;
char *word = (char *)malloc(sizeof(char));
int i;
dbmsg = dbus_message_new_signal("/client/signal/Object", "client.signal.Type", "Test");
scanf("%s", word);
if (!dbus_message_append_args(dbmsg, DBUS_TYPE_STRING, &word, DBUS_TYPE_INVALID)) {
return -1;
}
if (!dbus_connection_send(dbconn, dbmsg, NULL)) {
return -1;
}
dbus_connection_flush(dbconn);
printf("send message %s\n", word);
dbus_message_unref(dbmsg);
return 0;
}
int main(int argc, char *argv[])
{
DBusError dberr;
DBusConnection *dbconn;
dbus_error_init(&dberr);
dbconn = dbus_bus_get(DBUS_BUS_SESSION, &dberr);
if (!dbus_connection_add_filter(dbconn, filter_func, NULL, NULL)) {
return -1;
}
db_send(dbconn);
while(dbus_connection_read_write_dispatch(dbconn, -1)) {
db_send(dbconn);
}
dbus_connection_unref(dbconn);
return 0;
}
You're communicating only with signals at the moment, which don't have a return value.
In client.c, use dbus_message_new_method_call instead of dbus_message_new_signal, and in server.c you probably have to change type='signal' to type='method_call'.