I want to know when I need to free a pointer that is returned from EFI functions
EFI_DEVICE_PATH_PROTOCOL *
BmExpandFileDevicePath (
IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
IN EFI_DEVICE_PATH_PROTOCOL *FullPath
)
{
EFI_STATUS Status;
UINTN Index;
UINTN HandleCount;
EFI_HANDLE *Handles;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
UINTN MediaType;
EFI_DEVICE_PATH_PROTOCOL *NextFullPath;
BOOLEAN GetNext;
EfiBootManagerConnectAll ();
Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiSimpleFileSystemProtocolGuid, NULL, &HandleCount, &Handles);
if (EFI_ERROR (Status)) {
HandleCount = 0;
Handles = NULL;
}
GetNext = (BOOLEAN)(FullPath == NULL);
NextFullPath = NULL;
//
// Enumerate all removable media devices followed by all fixed media devices,
// followed by media devices which don't layer on block io.
//
for (MediaType = 0; MediaType < 3; MediaType++) {
for (Index = 0; Index < HandleCount; Index++) {
Status = gBS->HandleProtocol (Handles[Index], &gEfiBlockIoProtocolGuid, (VOID *) &BlockIo);
if (EFI_ERROR (Status)) {
BlockIo = NULL;
}
if ((MediaType == 0 && BlockIo != NULL && BlockIo->Media->RemovableMedia) ||
(MediaType == 1 && BlockIo != NULL && !BlockIo->Media->RemovableMedia) ||
(MediaType == 2 && BlockIo == NULL)
) {
NextFullPath = AppendDevicePath (DevicePathFromHandle (Handles[Index]), FilePath);
if (GetNext) {
break;
} else {
GetNext = (BOOLEAN)(CompareMem (NextFullPath, FullPath, GetDevicePathSize (NextFullPath)) == 0);
FreePool (NextFullPath);
NextFullPath = NULL;
}
}
}
if (NextFullPath != NULL) {
break;
}
}
if (Handles != NULL) {
FreePool (Handles);
}
return NextFullPath;
}
for example, In this code, can I free Handles after calling HandleProtocol and still be able to use BlockIo?
Is there a document that explains the "pointer passing convention" of edk2 functions?
Thanks.
You have to look into the specification, if you are responsible to free the pointer there is a note.
For your LocateHandleBuffer example:
Buffer
A pointer to the buffer to return the requested array of handles that
support Protocol. This buffer is allocated with a call to the Boot
Service EFI_BOOT_SERVICES.AllocatePool(). It is the caller's
responsibility to call the Boot Service EFI_BOOT_SERVICES.FreePool()
when the caller no longer requires the contents of Buffer."
You can use the BlockIO protocols after you free the buffer, you are not freeing the handle instances (which would be a very bad idea), instead you are freeing an array of them.
Related
My application has 3 layers -downlayer, middlelayer and upperlayer. downlayer and upperlayer are decoupled. Data passes either this way upperlayer -> middlelayer -> downlayer, or this way downlayer -> middlelayer->upperlayer.
My code look like this:
UpperLayer.c
#include <middlelayer.h>
int upperReaddownData()
{
DATA_ST* readFromdown_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
if(readFromdown_ptr != NULL)
{
int retVal = GetFunction(readFromdown_ptr, UP);
if (retVal == 0) {
bool value;
memcpy(&value, readFromdown_ptr->continousData, sizeof(bool));
printf("Data read %s\t",
value ? "true" : "false");
printf("\n");
}
// I get error here
free(readFromdown_ptr);
return 0;
}
else {
return -1;
}
}
int UpperWritedownData()
{
bool random = rand() % 2;
DATA_ST* dumpTodown_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
if (dumpTodown_ptr != NULL) {
size_t size_data = (size_t)sizeof(bool);
memcpy(dumpTodown_ptr->continousData, &random, size_data);
// size of data has to be mentioned while writing to memory
dumpTodown_ptr->packetSize = size_data;
int retVal = SetFunction(dumpTodown_ptr, DOWN);
// i get error here
free(dumpTodown_ptr);
return 0;
}
else {
return -1;
}
}
middlelayer.h
#define UP 0x00
#define DOWN 0x01
#define BUFFER_SIZE 2
typedef struct
{
size_t packetSize;
uint8_t continousData[80];
}DATA_ST;
typedef struct
{
bool isDataAlreadyRead;
DATA_ST Data;
}PACKET_HEADER_ST;
int Init();
int GetFunction(DATA_ST* packet, uint8_t target);
int SetFunction(DATA_ST* packet, uint8_t target);
int DeInit();
middlelayer.c
#include<middlelayer.h>
#define COPY_MEMORY(Dst,Src,Size) memcpy(Dst,Src,Size)
static PACKET_HEADER_ST* BUFFER[BUFFER_SIZE];
int Init()
{
uint8_t instance;
for (instance = 0; instance < BUFFER_SIZE; instance++) {
BUFFER[instance] = (PACKET_HEADER_ST*)calloc(1,sizeof(PACKET_HEADER_ST));
if (BUFFER[instance] != NULL)
{
BUFFER[instance]->isDataAlreadyRead = true;
}
else
{
return -1;
}
}
return 0;
}
int GetFunction(DATA_ST* packet,uint8_t target)
{
DATA_ST* currPacket = NULL;
if (BUFFER[target]->isDataAlreadyRead == false)
{
// not getting how to use memcpy properly
//currPacket = (DATA_ST*)&BUFFER[target]->Data;
//COPY_MEMORY(packet->continousData, currPacket->continousData, sizeof(BUFFER[target]->Data.packetSize));
//packet->packetSize = currPacket->packetSize;
//BUFFER[target]->isDataAlreadyRead = true;
*packet = BUFFER[target]->Data;
}
else
{
return -1;
}
return 0;
}
int SetFunction(DATA_ST* packet, uint8_t target)
{
//COPY_MEMORY(BUFFER[target]->Data.continousData, packet->continousData,sizeof(packet->packetSize));
//BUFFER[target]->Data.packetSize = packet->packetSize;
//BUFFER[target]->isDataAlreadyRead = false;
BUFFER[target]->Data = *packet;
BUFFER[target]->isDataAlreadyRead = false;
return 0;
}
int DeInit()
{
uint8_t instance;
for (instance = 0; instance < BUFFER_SIZE; instance++) {
free(BUFFER[instance]);
}
return 0;
}
lowerlayer.c
#include<middlelayer.h>
int downReadUpData(void)
{
DATA_ST* readFromDown_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
if (readFromDown_ptr != NULL)
{
int retVal = GetFunction(readFromDown_ptr,DOWN);
if (retVal == 0) {
bool mybool;
memcpy(&mybool, readFromDown_ptr->continousData,readFromDown_ptr->packetSize);
// do something with data
}
// i get error here
free(readFromDown_ptr);
readFromDown_ptr = NULL;
return retVal;
}
else {
return -1;
}
}
//send dummy data to Up
int downWriteUpData(void)
{
static bool race_b = false;
DATA_ST* dumpToUp_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
if (dumpToUp_ptr != NULL) {
size_t size_data = (size_t)sizeof(bool);
memcpy(dumpToUp_ptr->continousData, &race_b, size_data);
// size of data has to be mentioned while writing to memory
dumpToUp_ptr->packetSize = size_data;
int retVal = SetFunction(dumpToUp_ptr, UP);
// i get error here
free(dumpToUp_ptr);
dumpToUp_ptr = NULL;
race_b = !race_b;
return retVal;
}
else {
return -1;
}
}
I call UpperWritedownData function, it calls SetFunction, then i call downReadUpData Function and read the data passed by Upper layer.
I want to design the middlelayer like this : you pass the data of any datatype to the middlelayer(uint8_t array can hold any datatype), during Init ,the middlelayer is allocated some memory and i have the pointer of BUFFER[Up]->Data or BUFFER[DOWN]->Data and these pointers are constant and should not change throughout the program. Now upper/down layer gives data (SetFunction) , i dump it in my preallocated memory, then after some time, down/upper asks the data i copy the data from my preallocated memory and give it.Now I just need to store the recent data hence i have not implemented queues also i am overwriting and once the data is read , i dont care about it and I have to discard it.
What I tried:
I tried using memcpy and copy the pointer to BUFFER[x]->Data and I have commented that part of code as you can see.It did not work because memcpy copies the pointer to BUFFER[target]->Databut i wanted to copy just the contents.When I tried to use free(pointer), i get heap corruption error message.I am having trouble in using memory allocation. Kindly provide inputs.
There is a bug in this malloc:
DATA_ST* readFromdown_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
You define readFromdown_ptr as a pointer to DATA_ST. So you want to make it point to a memory block that can hold a DATA_ST but you only allocate memory for a pointer to DATA_ST because you do sizeof(DATA_ST*).
Change it to:
DATA_ST* readFromdown_ptr = malloc(sizeof(DATA_ST));
or better.. change it to:
DATA_ST* readFromdown_ptr = malloc(sizeof *readFromdown_ptr);
The same applies to the line:
DATA_ST* dumpToUp_ptr = (DATA_ST*)malloc(sizeof(DATA_ST*));
I am using stm32f4 microproccessor and lwip library for the some ethernet process.
I have a problem with dynamic memory allocation. For some reason when I send ping to my hardware, this device experience Hardfault problem after 1 hour.
These are my firmware routine in main.c
while(1)
{
uint8_t * incomingData = ethernetif_input(&gnetif);
if(incomingData != NULL)
{
if(incomingData[0] == 0x01)
{
// doing some process
}
incomingData = NULL;
free(incomingData)
}
}
in ethernetif.c :
uint8_t * ethernetif_input(struct netif *netif)
{
struct pbuf *p;
p = low_level_input(netif);
if (p == NULL) {
return NULL;
}
uint8_t * data = (uint8_t*)(malloc(sizeof( uint8_t) * 61U));
if ((memcmp (p->payload, EXPECTED_ETHERNET_FRAME, 6) == 0))
{
for(int i = 0; i < 61; i++)
{
data[i]=(((uint8_t*)p->payload)[i]);
}
}
else
{
err = netif->input(p, netif);
data = NULL;
free(data);
if (err != ERR_OK)
{
pbuf_free(p);
p = NULL;
}
{
if(p != NULL)
{
pbufFreeErr = pbuf_free(p);
if( !(_Bool)pbufFreeErr)
{
}
}
return data;
}
You're running out of memory.
As already mentioned in the comments: data=NULL; free(data) does not make sense. It says forget what data pointed to and then do nothing with it.
You should first free(data)before setting it to NULL. That will make the memory pointed to by data available to future malloccalls.
And you should also call pbuf_free in all cases, you will run out of memory if you don't.
As a final remark, do not use a for loop to copy the buffer, use memcpy.
i have a simple problem with my c code .... I want to call the variable with call by reference.
I have this function:
void createHeader(HEADER *yourHeader)
{
yourHeader = malloc(sizeof(HEADER));
if (yourHeader == NULL)
printError();
yourHeader->first = NULL;
yourHeader->last = NULL;
yourHeader->length = 0;
}
My main-call:
createHeader(&header);
if (header == NULL)
exit(-1);
Now I have the following problem: "The program '[6044] My-C-Project.exe' has exited with code -1 (0xffffffff)", so that means my function createHeader doens't work ... Can someone please explain what's the mistake is?
Regards
Alex
Change the function to:
HEADER *createHeader(void)
{
HEADER *yourHeader = malloc(sizeof(HEADER));
if (yourHeader == NULL)
printErrorAndExit();
yourHeader->first = NULL;
yourHeader->last = NULL;
yourHeader->length = 0;
return yourHeader;
}
Use:
Header *header = createHeader();
if (header == NULL)
exit(-1);
Alternatively, use a pointer to a pointer as the argument:
void createHeader(HEADER **yourHeader)
{
*yourHeader = malloc(sizeof(HEADER));
if (*yourHeader == NULL)
printError();
(*yourHeader)->first = NULL;
(*yourHeader)->last = NULL;
(*yourHeader)->length = 0;
}
Use:
Header *header = NULL;
createHeader(&header);
if (header == NULL)
exit(EXIT_FAILURE);
These two techniques can be applied to most 'allocate pointer' operations — creating linked lists is a particularly common variation. Note that fopen() and fclose() match the first model; the allocator (fopen()) takes some arguments to tell it what to do and the function returns a pointer to a structure that can be used and eventually passed to fclose() for release.
Note that printErrorAndExit() must not return. Or, if it does, the functions have to be revised:
HEADER *createHeader(void)
{
HEADER *yourHeader = malloc(sizeof(HEADER));
if (yourHeader == NULL)
printError();
else
{
yourHeader->first = NULL;
yourHeader->last = NULL;
yourHeader->length = 0;
}
return yourHeader;
}
It might be better for the function not to print any error message — that limits its reusability, in general.
HEADER *createHeader(void)
{
HEADER *yourHeader = malloc(sizeof(HEADER));
if (yourHeader != NULL)
{
yourHeader->first = NULL;
yourHeader->last = NULL;
yourHeader->length = 0;
}
return yourHeader;
}
The alternative design should probably return a status instead of nothing, so you can test the function result directly:
int createHeader(HEADER **yourHeader)
{
int rc = 0;
*yourHeader = malloc(sizeof(HEADER));
if (*yourHeader == NULL)
rc = -1; /* Or perhaps errno */
else
{
(*yourHeader)->first = NULL;
(*yourHeader)->last = NULL;
(*yourHeader)->length = 0;
}
return rc;
}
Use:
if (createHeader(&header) != 0)
…report error and bail out…
Using 0 for success and non-zero for failure is very common (many Unix system calls fall into this category). Very often, a negative return value indicates failure, especially if a positive value can be used for success — think open(). But the POSIX pthread functions frequently return a positive error number on failure and zero on success.
My program crached on Eclipse when i try to free my object - PokemonTrainer.I have tried the solution in this article, but it didn't help.
PokemonTrainer pokemonTrainerCreate(char* name, Pokemon initial_pokemon,
int max_num_local, int max_num_remote)
{
PokemonTrainer trainer = malloc(sizeof(PokemonTrainer));
if ((name == NULL) || (initial_pokemon == NULL) || (trainer == NULL) ||
(max_num_local < 0) || (max_num_remote < 0))
return NULL;
char tmp_name[strlen(name)];
strcpy(tmp_name, name);
trainer->name = tmp_name;
trainer->max_num_local = max_num_local;
trainer->max_num_remote = max_num_remote;
trainer->pokemons_local = malloc(sizeof(Pokemon)
trainer->max_num_local);
trainer->pokemons_remote = malloc(sizeof(Pokemon)
trainer->max_num_remote);
if (trainer->pokemons_remote == NULL) {
free(trainer->pokemons_local);
return NULL;
} else if (trainer->pokemons_local == NULL) {
free(trainer->pokemons_remote);
return NULL;
}
trainer->pokemons_local[0] = pokemonCopy(initial_pokemon);
trainer->curr_num_local = 1;
trainer->curr_num_remote = 0;
return trainer;
}
void pokemonTrainerDestroy(PokemonTrainer trainer)
{
if (trainer == NULL)
return;
if (trainer->curr_num_local > 0)
for (int i = trainer->curr_num_local - 1; i >= 0; i--)
pokemonDestroy(trainer->pokemons_local[i]);
if (trainer->curr_num_remote > 0)
for (int i = trainer->curr_num_remote - 1; i >= 0; i--)
pokemonDestroy(trainer->pokemons_remote[i]);
free (trainer); // here it's crashed
}
It is during the execution of free() in the stack that I am getting a "No source available for "ntdll!RtlpNtEnumerateSubKey() at 0x77cf04e5" error.
PokemonTrainer trainer = malloc(sizeof(PokemonTrainer)); is unlikely to work properly since you're allocating the size of the pointer, not the real data.
You won't have enough storage => undefined behaviour happens, and for you it happens when freeing the memory (corrupt memory list)
I would do this:
PokemonTrainer trainer = malloc(sizeof(*PokemonTrainer));
so the sizeof takes the size of the structure pointed by PokemonTrainer.
EDIT: for completeness, BLUEPIXY suggests that you've missing 1 byte here (because of null-termination char):
char tmp_name[strlen(name)];
strcpy(tmp_name, name);
and moreover this allocated space is temporary, so I'd suggest:
char *tmp_name = strdup(name);
which will allocate the correct size and performs a dynamic allocation that stays valid even after returning from the routine.
I'm writing a service in Linux using c, so I need to keep the memory usage stable.
But after tracing a day, the memory raise.
If I monitor from the System Monitor in Linux, it raise 1M and the mem%(0 -> 0.1).
In pmap command, it raise 1M, too.
I have use valgrind to check if there are any memory leak, and it report none if I run once.
If I start the service and use valgrind, it will report that I free invalid pointer.
So, I think it should have something to do about my pointer.
struct list {
int no;
BYTE parm[SLEN];
struct list *next;
};
struct list *memory_current;
struct list *memory_head;
struct list *memory_prev;
int getMemoryUsage(int sendCmd) {
pthread_mutex_lock(&lock);
FILE *fp = NULL;
BYTE buffer[10] = "";
BYTE memorys[10] = "";
int flag = 0;
TRY {
if ((fp = popen("free_data=$(free -m | grep Mem);total=$(echo $free_data | cut -f2 -d' ');"
"free_data=$(free -m | grep 'buffers/cache');buffers=$(echo $free_data | cut -f3 -d' ');echo $(($buffers*100/$total))", "r")) == NULL) {
THROW(CMD_NOT_FND);
}
else {
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
strcat(memorys, buffer);
memory_current = (struct list *)malloc(sizeof(struct list));
if (memory_current == NULL) {
THROW(MALLOC_ERROR);
}
memory_current->next = NULL;
strncpy(memory_current->parm, buffer, SLEN -1);
memory_current->parm[SLEN -1] = '\0';
if (memory_head == NULL)
memory_head = memory_current;
else
memory_prev->next = memory_current;
memory_prev = memory_current;
memset(buffer, 0, sizeof(buffer));
flag = 1;
}
if (flag == 0)
THROW(CMD_NOT_FND);
}
}
CATCH (CMD_NOT_FND) {
memorys[0] = 'n';
memorys[1] = '/';
memorys[2] = 'a';
printf("Memory Usage % : %s\n", memorys);
printLog("Memory Usage % ->", memorys);
}
CATCH (MALLOC_ERROR) {
memorys[0] = 'n';
memorys[1] = '/';
memorys[2] = 'a';
printf("Memory Usage malloc error : %s\n", memorys);
printLog("Memory Usage malloc error ->", memorys);
}
FINALLY {
pclose(fp);
// printf("Memory Usage % : %s\n", memorys);
// printf("Memory Usage length %d\n", strlen(memorys));
}
ETRY;
if (sendCmd == 1) {
if (flag != 0) {
memory_current = memory_head;
int totalMemory = 0;
int count = 0;
int avg = 0;
int perc = 0;
BYTE avg_memory[10] = "";
while (memory_current != NULL) {
sscanf(memory_current->parm, "%d", &perc);
totalMemory += perc;
memory_current = memory_current->next;
count++;
}
avg = totalMemory / count;
snprintf(avg_memory, sizeof(avg_memory), "%d", avg); ;
strcat(avg_memory, ";");
printf("Memory Usage % : %s\n", avg_memory);
printLog("Memory Usage % ->", avg_memory);
// free linked list
memory_current = memory_head;
while (memory_current != NULL) {
memory_prev = memory_current;
memory_current = memory_current->next;
free(memory_prev);
memory_prev = NULL; //fix dangling
}
head_memory = NULL; //fix dangling
current_memory = NULL; //fix dangling
}
}
pthread_mutex_unlock(&lock);
return 0;
}
I have the global pointer to keep record the memory usage in a timer, and I will use the result and clear the list in a interval of time.
I use the same way to use in other function and the memory usage is fine, but the pointers are local and will free at the end.
Could you please help to advice or pointer out what is wrong about my pointer usage.
Thanks.
[Update]
I found that this might be a dangling pointer, so I set the pointer to NULL after the free.
So far the memory won't raise, but I'll keep watching it for more days.
Solved
The memory won't raise again, so I guess it's the dangling pointer issue.
memory_current, memory_head and memory_prev were not initialized to NULL.
you check:
if (memory_head == NULL)
when memory_head was not initialized, therefore you maybe loose some memory allocations
also look like they should be local variables, not global.