The Notorious Dynamic allocation of pointers to arrays of structures - c

I've a long version of a program that uses this code and a short version. This is the short version and oddly, this code runs perfectly fine in short version program, but because I get an access violation in the larger version, I get the feeling something is wrong. Does anyone see anything terribly wrong (that might lead to data corruption and/or access violation errors) with the following code? Or is this alright?
char strlist[5][11] = {
{ "file01.txt" },
{ "file02.txt" },
{ "file03.txt" },
{ "file04.txt" },
{ "file05.txt" }
};
typedef struct DYNAMEM_DATA {
char *string;
int strlen;
} DYNAMEM_DATA;
typedef struct DYNAMEM_STRUCT {
struct DYNAMEM_DATA **data;
int num_elements;
} DYNAMEM_STRUCT;
DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist)
{
DYNAMEM_STRUCT *ds = (DYNAMEM_STRUCT *)calloc(1, sizeof(DYNAMEM_STRUCT));
wchar_t wstring[128];
char len[3];
int i;
ds->data = (DYNAMEM_DATA **)calloc(num_elements, sizeof(DYNAMEM_DATA *));
ds->num_elements = num_elements;
for(i = 0; i < num_elements; i++) {
ds->data[i] = (DYNAMEM_DATA *)calloc(1, sizeof(DYNAMEM_DATA));
ds->data[i]->string = (char *)calloc(1, strlen(&strlist[i*11])+5);
ds->data[i]->strlen = strlen(&strlist[i*11]);
sprintf(ds->data[i]->string, "%s, %d", &strlist[i*11], ds->data[i]->strlen);
mbstowcs(wstring, ds->data[i]->string, 128);
MessageBox(NULL, wstring, TEXT("Error"), MB_OK);
}
return ds;
}

This code runs, produces 5 'Error' messages (which is to be expected), and doesn't leak any memory. Running valgrind (3.7.0) on Mac OS X 10.7.4 (using GCC 4.7.1), it is given a clean bill of health.
The problem is not, apparently, in this version of the code.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <wchar.h>
char strlist[5][11] = {
{ "file01.txt" },
{ "file02.txt" },
{ "file03.txt" },
{ "file04.txt" },
{ "file05.txt" }
};
typedef struct DYNAMEM_DATA {
char *string;
int strlen;
} DYNAMEM_DATA;
typedef struct DYNAMEM_STRUCT {
struct DYNAMEM_DATA **data;
int num_elements;
} DYNAMEM_STRUCT;
enum { MB_OK = 0 };
static void destroy_dynamem_data(DYNAMEM_DATA *dd)
{
free(dd->string);
free(dd);
}
static void destroy_dynamem_struct(DYNAMEM_STRUCT *ds)
{
for (int i = 0; i < ds->num_elements; i++)
destroy_dynamem_data(ds->data[i]);
free(ds->data);
free(ds);
}
static void MessageBox(const void *null, const wchar_t *wcs, const char *ncs, int status)
{
if (null == 0 || status == MB_OK)
fprintf(stderr, "%s\n", ncs);
else
fwprintf(stderr, L"%s\n", wcs);
}
static const char *TEXT(const char *arg) { return arg; }
extern DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist);
DYNAMEM_STRUCT *create_dynamem_struct(int num_elements, char *strlist)
{
DYNAMEM_STRUCT *ds = (DYNAMEM_STRUCT *)calloc(1, sizeof(DYNAMEM_STRUCT));
wchar_t wstring[128];
//char len[3];
int i;
ds->data = (DYNAMEM_DATA **)calloc(num_elements, sizeof(DYNAMEM_DATA *));
ds->num_elements = num_elements;
for(i = 0; i < num_elements; i++) {
ds->data[i] = (DYNAMEM_DATA *)calloc(1, sizeof(DYNAMEM_DATA));
ds->data[i]->string = (char *)calloc(1, strlen(&strlist[i*11])+5);
ds->data[i]->strlen = strlen(&strlist[i*11]);
sprintf(ds->data[i]->string, "%s, %d", &strlist[i*11], ds->data[i]->strlen);
mbstowcs(wstring, ds->data[i]->string, 128);
MessageBox(NULL, wstring, TEXT("Error"), MB_OK);
}
return ds;
}
int main(void)
{
DYNAMEM_STRUCT *ds = create_dynamem_struct(5, strlist[0]);
destroy_dynamem_struct(ds);
return 0;
}

Related

C structure printing wrong value even after initializing properly

In the program below, I am allocating memory for pointer to pointer properly and then allocating individual pointers and setting values properly, even though I am getting the garbage value to one of the structure member. I don't understand where exactly I am going wrong.
The sample output of below program is:
***CK: H2 nSupport: 0
CK: H2 nSupport: 1303643608
CK: FR2 nSupport: 0
CK: H2 nSupport: 1303643608
CK: FR2 nSupport: 0
***CK: SP2 nSupport: 0
I don't understand how I am getting the value 1303643608, though it is set properly at the beginning.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NOK 15
#define ML 100
typedef struct sample_test_for_ties_t
{
char sender[NOK];
char receiver[NOK];
char message[ML];
}sample_test_for_ties;
typedef struct CUOfS_t{
char cK[NOK];
char eK[NOK];
char nK[NOK];
char AL[ML];
int nSupport;
}CUOfS;
CUOfS **Btenders = NULL;
sample_test_for_ties test_ties[] = {
{"H2","ICY", "fmaabghijklmmcdenoopqrstuvwxyz"},
{"FR2","AIY", "fmaabghijklmmcdenoopqrstuvwxyz"},
{"SP2","LAY", "fmaabghijklmmcdenoopqrstuvwxyz"},
{"H30","ICY", "fmaabghijklmmcdenoopqrstuvwxyz"},
{"F30","AIY", "fmaabghijklmmcdenoopqrstuvwxyz"},
{"W30","LAY", "fmaabghijklmmcdenoopqrstuvwxyz"},
};
void InitBtenders(int numOfBCtenders)
{
int count =0;
if(!Btenders)
{
if(Btenders = (CUOfS **)malloc(sizeof (**Btenders) * numOfBCtenders))
{
while(count < numOfBCtenders)
{
Btenders[count] = NULL;
count++;
}
}
else
{
printf("Malloc failed\n");
}
}
}
void freeBtenders(int numOfBCtenders)
{
int count =0;
if(Btenders)
{
while(count<numOfBCtenders)
{
if(Btenders[count]) {
free(Btenders[count]);
Btenders[count] = NULL;
}
count++;
}
free(Btenders);
Btenders = NULL;
}
}
void UpdateBtendersInfo(char *aContenders)
{
static int counter =0;
if(Btenders)
{
if(Btenders[counter] == NULL) {
Btenders[counter] = (CUOfS *)malloc(sizeof (Btenders[counter]));
if(Btenders[counter])
{
strcpy(Btenders[counter]->cK,aContenders);
strcpy(Btenders[counter]->eK,"\0");
strcpy(Btenders[counter]->nK,"\0");
memset(Btenders[counter]->AL,0,sizeof(Btenders[counter]->AL));
Btenders[counter]->nSupport = 0;
counter++;
}
else
{
printf("Insufficient memory for Btender\n");
}
}
}
else
{
printf("Looks like memory not allocated for Btenders\n");
}
int count =0;
while(count <counter && Btenders[count])
{
printf("***CK: %s nSupport: %d\n",Btenders[count]->cK,Btenders[count]->nSupport);
count++;
}
printf("\n");
}
int main()
{
int numOfBCtenders = 3;
int noc =0;
InitBtenders(numOfBCtenders);
while(noc < numOfBCtenders)
{
UpdateBtendersInfo(test_ties[noc].sender);
noc++;
}
freeBtenders(numOfBCtenders);
return 0;
}
I expect
***CK: H2 nSupport: 0
But I am getting
***CK: H2 nSupport: 1303643608
The way you allocate memory for Btenders is incorrect.
Btenders = (CUOfS **)malloc(sizeof (**Btenders) * numOfBCtenders) // WRONG
sizeof (**Btenders) is the same as sizeof(CUOfS), but you need sizeof(CUOfS*) :
Btenders = (CUOfS **)malloc(sizeof (*Btenders) * numOfBCtenders) // FIXED
Similarly for :
Btenders[counter] = (CUOfS *)malloc(sizeof (Btenders[counter])); // WRONG
sizeof (Btenders[counter]) is the same as sizeof(CUOfS*), but you need sizeof(CUOfS) :
Btenders[counter] = (CUOfS *)malloc(sizeof (*(Btenders[counter]))); // FIXED

printf shows wrong output, strange question mark at the end of line [C]

This code trying to perform queue, but that's queue has two fields: number and word. My problem is that field "word" prints incorrectly(field "number" is fine)
Expected output:
22
abc
12
efg
654
xyz
Unfortunately output looks like this
https://ibb.co/gjF446F
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define MAX_capacity 1000
#define Max_len_napis 100
typedef struct{
int number;
char word[];
} data;
data intArray[MAX_capacity];
int peak = 0;
int rear = -1;
int itemCount = 0;
int front() {
return intArray[peak].number;
}
bool isEmpty() {
return itemCount == 0;
}
bool isFull() {
return itemCount == MAX_capacity;
}
int size() {
return itemCount;
}
void insert(data x) {
if(!isFull()) {
if(rear == MAX_capacity-1) {
rear = -1;
}
int indeks = ++rear;
intArray[indeks].number = x.number;
strcpy (intArray[indeks].word, x.word);
itemCount++;
}
}
data remove() {
data dat = intArray[peak++];
if(peak == MAX_capacity) {
peak = 0;
}
itemCount--;
return dat;
}
void print(int N){
for(int i=0;i<N;i++){
data n = remove();
printf("%d\n",n.number);
printf("%s\n",n.word); // that's line doesn't work correctly
}
}
int main() {
data tab[3];
tab[0].number = 22;
strcpy (tab[0].word, "abc");
insert(tab[0]);
tab[1].number = 12;
strcpy (tab[1].word, "efg");
insert(tab[1]);
tab[2].number = 654;
strcpy (tab[2].word, "xyz");
insert(tab[2]);
int siz = size();
print(siz);
return 0;
}
I think that printf("%s\n",n.word) is not work correctly. But if I dont use struct, all works properly.
You need to allocate memory for word. For example like this:
typedef struct{
int number;
char word[100];
} data;
Better way is to allocate memory for word dynamically.
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define MAX_capacity 1000
#define Max_len_napis 100
typedef struct{
int number;
char word[100];
} data;
data intArray[MAX_capacity];
int peak = 0;
int rear = -1;
int itemCount = 0;
int front() {
return intArray[peak].number;
}
bool isEmpty() {
return itemCount == 0;
}
bool isFull() {
return itemCount == MAX_capacity;
}
int size() {
return itemCount;
}
void insert(data x) {
if(!isFull()) {
if(rear == MAX_capacity-1) {
rear = -1;
}
int indeks = ++rear;
intArray[indeks].number = x.number;
strcpy (intArray[indeks].word, x.word);
itemCount++;
}
}
data remove() {
data dat = intArray[peak++];
if(peak == MAX_capacity) {
peak = 0;
}
itemCount--;
return dat;
}
void print(int N){
for(int i=0;i<N;i++){
data n = remove();
printf("%d\n",n.number);
printf("%s\n",n.word); // that's line doesn't work correctly
}
}
int main() {
data tab[3];
tab[0].number = 22;
strcpy (tab[0].word, "abc");
insert(tab[0]);
tab[1].number = 12;
strcpy (tab[1].word, "efg");
insert(tab[1]);
tab[2].number = 654;
strcpy (tab[2].word, "xyz");
insert(tab[2]);
int siz = size();
print(siz);
return 0;
}

C: How make a ArrayList implementation compatible with UNICODE_STRING data?

This following code must be able of add to ArrayList each process name since that current name still not is stored on list. The code of ArrayList implementation was from this reference, but have a trouble that, when changed int to UNICODE_STRING data (in Element structure, cause a sintaxe error on line:
if (e.data == list->elements[index].data) return index;
Error 1 error C2088: '==' : illegal for struct
of indexOf() routine.
So, how fix?
Code:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <Winternl.h>
#pragma comment(lib,"ntdll.lib")
typedef struct _SYSTEM_PROCESS_INFO
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
}SYSTEM_PROCESS_INFO, *PSYSTEM_PROCESS_INFO;
typedef struct
{
UNICODE_STRING data;
}Element;
typedef struct
{
int current;
int size;
int increment_rate;
Element *elements;
}ArrayList;
void initWithSizeAndIncRate(ArrayList *const list, int size, int rate)
{
list->size = size;
list->increment_rate = rate;
list->elements = (Element*)calloc(sizeof(Element), list->size);
list->current = -1;
}
void initWithSize(ArrayList *const list, int size)
{
initWithSizeAndIncRate(list, size, 50);
}
void init(ArrayList *const list)
{
initWithSize(list, 100);
}
void arraryCopy(void *dest, int dIndex, const void* src, int sIndex, int len, int destLen, size_t size)
{
uint8_t *udest = (uint8_t*)dest;
uint8_t *usrc = (uint8_t*)src;
dIndex *= size;
sIndex *= size;
len *= size;
destLen *= size;
if (src != dest)
{
memcpy(&udest[dIndex], &usrc[sIndex], len);
}
else
{
if (dIndex > sIndex)
{
uint8_t *tmp = (uint8_t*)calloc(destLen, size);
memcpy(tmp, &udest[dIndex], (destLen - dIndex));
memcpy(&udest[dIndex], &usrc[sIndex], len);
memcpy(&udest[dIndex + len], tmp, (destLen - dIndex));
free(tmp);
}
else if (sIndex > dIndex)
{
memcpy(&udest[dIndex], &usrc[sIndex], (destLen - sIndex) + 1);
}
else
return;
}
}
void clear(ArrayList *const list)
{
while (list->current >= 0)
{
list->elements[list->current] = (Element){ 0 };
list->current--;
}
}
void wide(ArrayList* const list)
{
list->size += list->increment_rate;
Element *newArr = (Element*)calloc(sizeof(Element), list->size);
arraryCopy(newArr, 0, list->elements, 0, list->current, list->size, sizeof(Element));
free(list->elements);
list->elements = newArr;
}
int add(ArrayList *const list, Element e)
{
if (++list->current < list->size)
{
list->elements[list->current] = e;
return 1;
}
else
{
wide(list);
list->elements[list->current] = e;
return 1;
}
return 0;
}
int indexOf(const ArrayList *const list, Element e)
{
int index = 0;
while (index <= list->current)
{
if (e.data == list->elements[index].data) return index;
index++;
}
return 0;
}
void printElement(const Element *const e)
{
printf("%i ", e->data);
}
void print(const ArrayList *const list)
{
int i;
for (i = 0; i <= list->current; i++)
{
Element e = list->elements[i];
printElement(&e);
}
printf("\n");
}
void clean(ArrayList *list)
{
free(list->elements);
}
int _tmain(int argc, _TCHAR* argv[])
{
NTSTATUS status;
PVOID buffer;
PSYSTEM_PROCESS_INFO spi;
ArrayList list;
init(&list);
buffer = VirtualAlloc(NULL, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!buffer)
{
printf("\nError: Unable to allocate memory for process list (%d)\n", GetLastError());
return -1;
}
printf("\nProcess list allocated at address %#x\n", buffer);
spi = (PSYSTEM_PROCESS_INFO)buffer;
if (!NT_SUCCESS(status = NtQuerySystemInformation(SystemProcessInformation, spi, 1024 * 1024, NULL)))
{
printf("\nError: Unable to query process list (%#x)\n", status);
VirtualFree(buffer, 0, MEM_RELEASE);
return -1;
}
while (spi->NextEntryOffset)
{
printf("\nProcess name: %wZ | Process ID: %d\n", &spi->ImageName, spi->ProcessId);
int i = indexOf(&list, (Element){ spi->ImageName });
if (i > 0)
print("process already in list \n");
else
add(&list, (Element){ spi->ImageName });
spi = (PSYSTEM_PROCESS_INFO)((LPBYTE)spi + spi->NextEntryOffset);
}
VirtualFree(buffer, 0, MEM_RELEASE);
print(&list);
clean(&list);
_getch();
return 0;
}
EDIT:
After answer of #Johnny Mopp below, now how call correctly indexof routine?
I tried like this:
int i = indexOf(&list, (Element){ &spi->ImageName.Buffer });
if (i >= 0)
printf("process already in list \n");
else
add(&list, (Element){ &spi->ImageName.Buffer });
but indexof say that all already is present in list, this is wrong!
EDIT 2:
Error after first edition of answer:
IMAGE
UNICODE_STRING is a struct. You'll have to either do memcmp() on the entire struct or wcscmp() on e.data.Buffer
int indexOf(const ArrayList *const list, Element e)
{
int index = 0;
while (index <= list->current)
{
// Check same lengths and then do string compare
if (e.data.Length == list->elements[index].data.Length &&
0 == wcsncmp(e.data.Buffer,
list->elements[index].data.Buffer,
list->elements[index].data.Length))
return index;
index++;
}
return 0;
}
// Update after comment
Here's the whole thing with proper memory management of the UNICODE_STRINGs
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <conio.h>
#include <windows.h>
#include <Winternl.h>
#pragma comment(lib,"ntdll.lib")
typedef struct _SYSTEM_PROCESS_INFO
{
ULONG NextEntryOffset;
ULONG NumberOfThreads;
LARGE_INTEGER Reserved[3];
LARGE_INTEGER CreateTime;
LARGE_INTEGER UserTime;
LARGE_INTEGER KernelTime;
UNICODE_STRING ImageName;
ULONG BasePriority;
HANDLE ProcessId;
HANDLE InheritedFromProcessId;
}SYSTEM_PROCESS_INFO, *PSYSTEM_PROCESS_INFO;
typedef struct
{
// Changed to be a pointer
UNICODE_STRING *data;
}Element;
typedef struct
{
int current;
int size;
int increment_rate;
Element *elements;
}ArrayList;
// Duplicate a UNICODE_STRING
UNICODE_STRING * CopyUString(UNICODE_STRING *src)
{
UNICODE_STRING *dest = (UNICODE_STRING *) malloc(sizeof UNICODE_STRING);
dest->Length = src->Length;
dest->MaximumLength = src->MaximumLength;
dest->Buffer = (PWSTR) malloc(sizeof WCHAR * dest->MaximumLength);
memcpy(dest->Buffer, src->Buffer, sizeof WCHAR * dest->MaximumLength);
return dest;
}
// Free a duplicated UNICODE_STRING
void FreeUString(UNICODE_STRING *src)
{
free(src->Buffer);
free(src);
}
void initWithSizeAndIncRate(ArrayList *const list, int size, int rate)
{
list->size = size;
list->increment_rate = rate;
list->elements = (Element*) calloc(sizeof(Element), list->size);
list->current = -1;
}
void initWithSize(ArrayList *const list, int size)
{
initWithSizeAndIncRate(list, size, 50);
}
void init(ArrayList *const list)
{
initWithSize(list, 100);
}
void arraryCopy(void *dest, int dIndex, const void* src, int sIndex, int len, int destLen, size_t size)
{
uint8_t *udest = (uint8_t*) dest;
uint8_t *usrc = (uint8_t*) src;
dIndex *= size;
sIndex *= size;
len *= size;
destLen *= size;
if (src != dest)
{
memcpy(&udest[dIndex], &usrc[sIndex], len);
}
else
{
if (dIndex > sIndex)
{
uint8_t *tmp = (uint8_t*) calloc(destLen, size);
memcpy(tmp, &udest[dIndex], (destLen - dIndex));
memcpy(&udest[dIndex], &usrc[sIndex], len);
memcpy(&udest[dIndex + len], tmp, (destLen - dIndex));
free(tmp);
}
else if (sIndex > dIndex)
{
memcpy(&udest[dIndex], &usrc[sIndex], (destLen - sIndex) + 1);
}
else
return;
}
}
void clear(ArrayList *const list)
{
while (list->current >= 0)
{
FreeUString(list->elements[list->current].data);
list->current--;
}
}
void wide(ArrayList* const list)
{
list->size += list->increment_rate;
Element *newArr = (Element*) calloc(sizeof(Element), list->size);
arraryCopy(newArr, 0, list->elements, 0, list->current, list->size, sizeof(Element));
free(list->elements);
list->elements = newArr;
}
int add(ArrayList *const list, Element *e)
{
if (++list->current < list->size)
{
list->elements[list->current].data = CopyUString(e->data);
return 1;
}
else
{
wide(list);
list->elements[list->current].data = CopyUString(e->data);
return 1;
}
return 0;
}
int indexOf(const ArrayList *const list, Element *e)
{
int index = 0;
while (index <= list->current)
{
// Check same lengths and then do string compare
if (e->data->Length == list->elements[index].data->Length &&
0 == wcsncmp(e->data->Buffer,
list->elements[index].data->Buffer,
list->elements[index].data->Length))
return index;
index++;
}
return 0;
}
void printElement(const Element *const e)
{
wprintf(L"%s ", e->data->Buffer);
}
void print(const ArrayList *const list)
{
int i;
for (i = 0; i <= list->current; i++)
{
Element e = list->elements[i];
printElement(&e);
}
printf("\n");
}
void clean(ArrayList *list)
{
free(list->elements);
}
int _tmain(int argc, _TCHAR* argv [])
{
NTSTATUS status;
PVOID buffer;
PSYSTEM_PROCESS_INFO spi;
ArrayList list;
init(&list);
buffer = VirtualAlloc(NULL, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (!buffer)
{
printf("\nError: Unable to allocate memory for process list (%d)\n", GetLastError());
return -1;
}
printf("\nProcess list allocated at address %#x\n", buffer);
spi = (PSYSTEM_PROCESS_INFO) buffer;
if (!NT_SUCCESS(status = NtQuerySystemInformation(SystemProcessInformation, spi, 1024 * 1024, NULL)))
{
printf("\nError: Unable to query process list (%#x)\n", status);
VirtualFree(buffer, 0, MEM_RELEASE);
return -1;
}
Element e;
while (spi->NextEntryOffset)
{
printf("\nProcess name: %wZ | Process ID: %d\n", &spi->ImageName, spi->ProcessId);
e.data = &(spi->ImageName);
int i = indexOf(&list, &e);
if (i > 0)
printf("process already in list \n");
else
add(&list, &e);
spi = (PSYSTEM_PROCESS_INFO) ((LPBYTE) spi + spi->NextEntryOffset);
}
VirtualFree(buffer, 0, MEM_RELEASE);
print(&list);
clean(&list);
_getch();
return 0;
}

C: Dynamically Allocated Struct Array Usage

Getting errors such as
stats.c:28:36: error: ‘factoryStats’ has no member named ‘candyConsumed’ factoryStatsArray[producer_number].candyConsumed++;
What I want to be able to achieve is to create an array of structs, then access it's members. Is this the wrong way to do it?
Tried using -> but that shouldn't and don't work since I'm storing structs, not pointers to structs.
#include "stats.h"
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int factoryNumber = 0;
int candyProduced = 0;
int candyConsumed = 0;
double minDelay = 0;
double avgDelay = 0;
double maxDelay = 0;
} factoryStats;
factoryStats *factoryStatsArray;
int NUM_FACTORIES = 0;
void stats_init (int num_producers) {
factoryStatsArray = malloc(sizeof(factoryStats) * num_producers);
NUM_FACTORIES = num_producers;
}
void stats_cleanup (void) {
free(factoryStatsArray);
}
void stats_record_produced (int factory_number) {
factoryStatsArray[factory_number].candyProduced++;
}
void stats_record_consumed (int producer_number, double delay_in_ms) {
factoryStatsArray[producer_number].candyConsumed++;
if (factoryStatsArray[producer_number].minDelay == 0) {
factoryStatsArray[producer_number].minDelay = delay_in_ms;
} else {
if (factoryStatsArray[producer_number].minDelay > delay_in_ms) {
factoryStatsArray[producer_number].minDelay = delay_in_ms;
}
}
if (factoryStatsArray[producer_number].maxDelay == 0) {
factoryStatsArray[producer_number].maxDelay = delay_in_ms;
} else {
if (factoryStatsArray[producer_number].maxDelay < delay_in_ms) {
factoryStatsArray[producer_number].maxDelay = delay_in_ms;
}
}
factoryStatsArray[producer_number].avgDelay+= delay_in_ms;
}
void stats_display(void) {
printf("%8s%10s%10s10s10s10s\n", "Factory#", "#Made", "#Eaten", "Min Delay[ms]", "Avg Delay[ms]", "Max Delay[ms]");
for (int i = 0; i < NUM_FACTORIES; i++) {
printf("%8d%8d%8d%10.5f%10.5f%10.5f",
factoryStatsArray[i].factoryNumber, factoryStatsArray[i].candyProduced,
factoryStatsArray[i].candyConsumed, factoryStatsArray[i].minDelay,
factoryStatsArray[i].avgDelay/factoryStatsArray[i].candyConsumed,
factoryStatsArray[i].maxDelay);
}
}
structs cannot be initialized this way. Remove all those = 0 in typedef struct { ... } factoryStats;. Afterwards it compiles as in http://ideone.com/uMgDzE .

Bug in valgrind? or my mistake?

So I wrote a toy program for fun, and at the I moment I finished debugging thinking I finally got everything right, the last check with valgrind gave me 2 errors for not freeing 2 blocks of memory. But the error message really does not make sense to me.
==7419== 80 bytes in 1 blocks are definitely lost in loss record 1 of 2
==7419== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7419== by 0x400C77: mj_Malloc (mj.c:19)
==7419== by 0x401761: main (choco.c:93)
==7419==
==7419== 80 bytes in 1 blocks are definitely lost in loss record 2 of 2
==7419== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7419== by 0x400C77: mj_Malloc (mj.c:19)
==7419== by 0x401776: main (choco.c:94)
==7419==
==7419== LEAK SUMMARY:
==7419== definitely lost: 160 bytes in 2 blocks
Line 94 and 93 in main is
mj_Thread *chocolateMakers = mj_Malloc(nMakers * sizeof *chocolateMakers);
mj_Thread *chocolateEaters = mj_Malloc(nEaters * sizeof *chocolateEaters);
which is freed by
mj_Free(chocolateEaters);
mj_Free(chocolateMakers);
mj_Malloc and mj_Free are simple wrappers for error checking. (mj_Free for consistency)
void *mj_Malloc(size_t size) {
void *p = malloc(size);
if (p == NULL) {
mj_Error("heap allocation failed");
}
return p;
}
void mj_Free(void *p) {
free(p);
}
You can see the whole code below if you want.
choco.c
#include "../mj.c"
typedef struct {
int n;
mj_BlockingQueue orderQueue;
mj_BlockingQueue deliveryQueue;
} *ChocolateArgument;
ChocolateArgument ChocolateArgumentCreate(int n, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
ChocolateArgument this = mj_Malloc(sizeof *this);
this->n = n;
this->orderQueue = orderQueue;
this->deliveryQueue = deliveryQueue;
return this;
}
int MakeChocolates(void *data) {
ChocolateArgument argument = (ChocolateArgument)data;
while (true) {
if (mj_BlockingQueueOut(argument->orderQueue) != NULL) {
printf("chocolate maker %i going home\n", argument->n);
break;
}
int milli = mj_RandomInt(1, 1000);
mj_Sleep(milli);
printf("new chocolate (maker %i, %.3f seconds)\n", argument->n, (double)milli / 1000.0);
int *pMakerNumber = mj_Malloc(sizeof *pMakerNumber);
*pMakerNumber = argument->n;
mj_BlockingQueueIn(argument->deliveryQueue, pMakerNumber);
}
mj_Free(data);
return EXIT_SUCCESS;
}
void HireChocolateMakers(mj_Thread **pMakers, int nMakers, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
*pMakers = mj_Malloc(nMakers * sizeof **pMakers);
for (int i = 0; i < nMakers; i += 1) {
ChocolateArgument argument = ChocolateArgumentCreate(i + 1, orderQueue, deliveryQueue);
(*pMakers)[i] = mj_ThreadCreate(MakeChocolates, argument);
}
printf("%i chocolate makers hired\n", nMakers);
}
int EatChocolates(void *data) {
ChocolateArgument argument = (ChocolateArgument)data;
int nOrders = mj_RandomInt(1, 10);
for (int i = 0; i < nOrders; i += 1) {
mj_BlockingQueueIn(argument->orderQueue, NULL);
}
printf("chocolate eater %i ordered %i chocolates\n", argument->n, nOrders);
for (int i = 1; i <= nOrders; i += 1) {
int *pMakerNumber = mj_BlockingQueueOut(argument->deliveryQueue);
printf("maker %i -> eater %i (%i / %i)\n", *pMakerNumber, argument->n, i, nOrders);
free(pMakerNumber);
}
printf("chocolate eater %i is satisfied\n", argument->n);
mj_Free(data);
return EXIT_SUCCESS;
}
void OrderChocolates(mj_Thread **pEaters, int nEaters, mj_BlockingQueue orderQueue, mj_BlockingQueue deliveryQueue) {
*pEaters = mj_Malloc(nEaters * sizeof **pEaters);
for (int i = 0; i < nEaters; i += 1) {
ChocolateArgument argument = ChocolateArgumentCreate(i + 1, orderQueue, deliveryQueue);
(*pEaters)[i] = mj_ThreadCreate(EatChocolates, argument);
}
}
void GoHome(mj_Thread *eaters, int nEaters, mj_Thread *makers, int nMakers, mj_BlockingQueue orderQueue) {
for (int i = 0; i < nEaters; i += 1) {
mj_ThreadWait(eaters[i]);
mj_ThreadDelete(eaters[i]);
}
printf("all chocolate eaters are satisfied\n");
for (int i = 0; i < nMakers; i += 1) {
mj_BlockingQueueIn(orderQueue, NULL + 1);
}
for (int i = 0; i < nMakers; i += 1) {
mj_ThreadWait(makers[i]);
mj_ThreadDelete(makers[i]);
}
}
int main(int argc, char **argv) {
if (argc != 3) {
mj_Error("not enough arguments");
}
int nMakers = atoi(argv[1]);
int nEaters = atoi(argv[2]);
mj_RandomSeed();
mj_BlockingQueue orderQueue = mj_BlockingQueueCreate();
mj_BlockingQueue deliveryQueue = mj_BlockingQueueCreate();
mj_Thread *chocolateMakers = mj_Malloc(nMakers * sizeof *chocolateMakers);
mj_Thread *chocolateEaters = mj_Malloc(nEaters * sizeof *chocolateEaters);
HireChocolateMakers(&chocolateMakers, nMakers, orderQueue, deliveryQueue);
OrderChocolates(&chocolateEaters, nEaters, orderQueue, deliveryQueue);
GoHome(chocolateEaters, nEaters, chocolateMakers, nMakers, orderQueue);
mj_BlockingQueueDelete(orderQueue);
mj_BlockingQueueDelete(deliveryQueue);
mj_Free(chocolateEaters);
mj_Free(chocolateMakers);
return 0;
}
mj.c
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <pthread.h>
#include <semaphore.h>
void mj_Error(char *errorMessage) {
fprintf(stderr, "%s\n", errorMessage);
exit(EXIT_FAILURE);
}
void *mj_Malloc(size_t size) {
void *p = malloc(size);
if (p == NULL) {
mj_Error("heap allocation failed");
}
return p;
}
void mj_Free(void *p) {
free(p);
}
typedef struct mj_QueueElement {
void *data;
struct mj_QueueElement *next;
} *mj_QueueElement;
mj_QueueElement mj_QueueElementCreate(void) {
mj_QueueElement this = mj_Malloc(sizeof *this);
return this;
}
void mj_QueueElementDelete(mj_QueueElement this) {
mj_Free(this);
}
typedef struct {
mj_QueueElement first;
mj_QueueElement last;
} *mj_Queue;
mj_Queue mj_QueueCreate(void) {
mj_Queue this = mj_Malloc(sizeof *this);
this->first = mj_QueueElementCreate();
this->last = this->first;
return this;
}
void mj_QueueDelete(mj_Queue this) {
mj_QueueElementDelete(this->first);
mj_Free(this);
}
void mj_QueueIn(mj_Queue this, void *data) {
this->last->data = data;
this->last->next = mj_QueueElementCreate();
this->last = this->last->next;
}
void *mj_QueueOut(mj_Queue this) {
mj_QueueElement temp = this->first;
void *data = temp->data;
this->first = this->first->next;
mj_QueueElementDelete(temp);
return data;
}
typedef pthread_mutex_t *mj_Mutex;
mj_Mutex mj_MutexCreate(void) {
mj_Mutex this = mj_Malloc(sizeof *this);
pthread_mutex_init(this, NULL);
return this;
}
void mj_MutexDelete(mj_Mutex this) {
pthread_mutex_destroy(this);
mj_Free(this);
}
void mj_MutexLock(mj_Mutex this) {
pthread_mutex_lock(this);
}
void mj_MutexUnlock(mj_Mutex this) {
pthread_mutex_unlock(this);
}
typedef sem_t *mj_Semaphore;
mj_Semaphore mj_SemaphoreCreate(int n) {
mj_Semaphore this = mj_Malloc(sizeof *this);
sem_init(this, 0, n);
return this;
}
void mj_SemaphoreDelete(mj_Semaphore this) {
sem_destroy(this);
mj_Free(this);
}
void mj_SemaphoreUp(mj_Semaphore this) {
sem_post(this);
}
void mj_SemaphoreDown(mj_Semaphore this) {
sem_wait(this);
}
typedef struct {
mj_Queue queue;
mj_Mutex inLock;
mj_Mutex outLock;
mj_Semaphore emptyBlocker;
} *mj_BlockingQueue;
mj_BlockingQueue mj_BlockingQueueCreate(void) {
mj_BlockingQueue this = mj_Malloc(sizeof *this);
this->queue = mj_QueueCreate();
this->inLock = mj_MutexCreate();
this->outLock = mj_MutexCreate();
this->emptyBlocker = mj_SemaphoreCreate(0);
return this;
}
void mj_BlockingQueueDelete(mj_BlockingQueue this) {
mj_QueueDelete(this->queue);
mj_MutexDelete(this->inLock);
mj_MutexDelete(this->outLock);
mj_SemaphoreDelete(this->emptyBlocker);
mj_Free(this);
}
void mj_BlockingQueueIn(mj_BlockingQueue this, void *data) {
mj_MutexLock(this->inLock);
mj_QueueIn(this->queue, data);
mj_SemaphoreUp(this->emptyBlocker);
mj_MutexUnlock(this->inLock);
}
void *mj_BlockingQueueOut(mj_BlockingQueue this) {
mj_MutexLock(this->outLock);
mj_SemaphoreDown(this->emptyBlocker);
void *data = mj_QueueOut(this->queue);
mj_MutexUnlock(this->outLock);
return data;
}
typedef pthread_t *mj_Thread;
typedef struct {
int (*function)(void *);
void *argument;
} *mj_ThreadInfo;
mj_ThreadInfo mj_ThreadInfoCreate(int (*function)(void *), void *argument) {
mj_ThreadInfo this = mj_Malloc(sizeof *this);
this->function = function;
this->argument = argument;
return this;
}
void *mj_ThreadFunction(void *data) {
mj_ThreadInfo info = (mj_ThreadInfo)data;
info->function(info->argument);
mj_Free(data);
return NULL;
}
mj_Thread mj_ThreadCreate(int (*function)(void *), void *argument) {
mj_Thread this = mj_Malloc(sizeof *this);
mj_ThreadInfo info = mj_ThreadInfoCreate(function, argument);
if (pthread_create(this, NULL, mj_ThreadFunction, info) != 0) {
mj_Error("failed to create thread");
}
return this;
}
void mj_ThreadDelete(mj_Thread this) {
mj_Free(this);
}
void mj_ThreadWait(mj_Thread this) {
pthread_join(*this, NULL);
}
void mj_Sleep(int milli) {
struct timespec time;
time.tv_sec = milli / 1000;
time.tv_nsec = (milli % 1000) * 1000000;
nanosleep(&time, NULL);
}
uint64_t mj_RandomInt_s;
uint64_t mj_RandomInt_s2;
void mj_RandomSeed(void) {
srand((unsigned)time(NULL));
mj_RandomInt_s = rand() * rand();
mj_RandomInt_s2 = rand() * rand() * rand();
}
int mj_RandomInt(int from, int to) {
if (from > to) {
mj_Error("invalid arguments");
}
uint64_t x = mj_RandomInt_s;
uint64_t y = mj_RandomInt_s2;
mj_RandomInt_s = y;
x ^= x << 23;
x ^= x >> 17;
x ^= y ^ (y >> 26);
mj_RandomInt_s2 = x;
return (int)((x + y) % (uint64_t)(to - from + 1)) + from;
}
You're allocating chocolateMakers twice (line 93 first and line 36 then) and chocolateEaters twice too (line 94 first and line 62 then). In both cases, you're overwriting the pointer resulting of the first allocation with the one resulting of the second allocation. When you free the allocated memory, you're doing it only once, with the pointers of the second allocations. The pointers of the first allocation are lost, the memory allocated is never freed.

Resources