freeing possible memory leak - c

I have been thinking in this for a while but I'm not sure if it's "safe" and possible.
Imagine something like this:
void genLeaks(void)
{
char* charLeakAddr;
charLeakAddr = (char*)malloc(sizeof(char) * 10);
strcpy(charLeakAddr, "Hello World");
}
As I understand this will create a memory leak because charLeakAddr is not released ( free (charLeakAddr); ).
Now in main :
int main(void)
{
genLeaks();
???????
return 0;
}
In the place marked with ??????? is there a way to create some kind of function that frees the memory allocated by charLeakAddr?
Thanks for your time.
Sorry but, how can I do to make the code good looking in the post :S ?
Thanks for your answers.
Somehow I produced this code and it seems to work ( I tested it in GCC with Code::Blocks in both Linux and Windows) Please take a look at it. Is it correct? or it is just crazy to try something like it?
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#define LEAKS_PATH_FILE "leaks.txt"
#define WIN_ERASE_LEAKS_FILE_COMMAND "erase leaks.txt"
#define UNIX_ERASE_LEAKS_FILE_COMMAND "rm leaks.txt"
#define __ASM__LEAK__DELETER__DEBUG
#define __UNIX__DEBUG__
unsigned int LEAKS = 0;
void regLeakAddr(void* memPtr, const char* fileName)
{
FILE* arch;
#ifdef __ASM__LEAK__DELETER__DEBUG
printf("\nMemory Leak : 0x%x\n", (void*)memPtr);
#endif
arch = fopen(fileName, "a");
if(arch)
{
fprintf(arch, "%d", (void*)memPtr);
fprintf(arch, "%c", '\n');
fclose(arch);
LEAKS++;
}
else
printf("ERROR IN FILE leaks.txt\n");
}
void assemblyDeleter(int numAddr)
{
#ifdef __ASM__LEAK__DELETER__DEBUG
printf("\nOnassemblyDeleter : 0x%x\n\n", numAddr);
#ifdef __UNIX__DEBUG__
getchar();
#else
system("pause");
#endif
#endif
char* deleter;
int* ptr = &numAddr;
printf("\n======> 0x%x\n\n", *ptr);
printf("\n======> 0x%x\n\n", deleter);
if((char*)*ptr > deleter)
{
printf("(ptr > deleter) : Offset : 0x%x\n", ((char*)*ptr - deleter));
deleter += ((char*)*ptr - deleter);
}
else
{
printf("(ptr < deleter) : Offset : 0x%x\n", (deleter - (char*)*ptr));
deleter += ((char*)*ptr - deleter);
}
printf("deleter =========> 0x%x\n", deleter);
#ifdef __ASM__LEAK__DELETER__DEBUG
puts(deleter);
#endif
free(deleter);
#ifdef __ASM__LEAK__DELETER__DEBUG
puts(deleter);
#endif
deleter = NULL;
ptr = NULL;
}
void freeMemory(void)
{
if(LEAKS == 0)
{
#ifdef __ASM__LEAK__DELETER__DEBUG
printf("NO LEAKS\n");
#endif
return;
}
FILE* arch;
int addr;
int i;
arch = fopen(LEAKS_PATH_FILE, "r");
if(arch == NULL)
{
#ifdef __ASM__LEAK__DELETER__DEBUG
printf("Error on file...\n");
#endif
return;
}
for(i = 0; i<LEAKS; i++)
{
fscanf(arch, "%d", &addr);
assemblyDeleter(addr);
}
fclose(arch);
#ifdef __UNIX__DEBUG__
system(UNIX_ERASE_LEAKS_FILE_COMMAND);
#else
system(WIN_ERASE_LEAKS_FILE_COMMAND);
#endif
}
void genLeakTrick(char** msg)
{
*msg = (char*)malloc(sizeof(char) * 17);
strcpy(*msg, "Hello World again");
printf("\n%s\n", *msg);
}
void genLeaks(void)
{
char* charLeakAddr;
charLeakAddr = (char*)malloc(sizeof(char) * 10);
strcpy(charLeakAddr, "Hello World");
printf("\n%s\n", charLeakAddr);
//free(charLeakAddr);
regLeakAddr(charLeakAddr, LEAKS_PATH_FILE);
char* charLeakAddr2;
genLeakTrick(&charLeakAddr2);
//free(charLeakAddr2);
regLeakAddr(charLeakAddr2, LEAKS_PATH_FILE);
}
int main(void)
{
genLeaks();
freeMemory();
return 0;
}

No, there is no way to free that memory. It's permanently lost (unless you can somehow find the pointer that was originally returned by malloc).
You can always just free it in genLeak since it's not being used for anything after that. If you return the pointer though, someone else is going to have to free it after it's used.
That's why in C library documentation whenever a pointer is returned, they tell you who the pointer is owned by and if you have to free it or not.

No way, until the genleak() return type is void. Modifying the return type and if the function returns a reference of charLeakAddr, it would be possible.
char* genleak()
{
char* charLeakAddr;
charLeakAddr = (char*)malloc(sizeof(char) * 10);
strcpy(charLeakAddr, "Hello World");
return charLeakAddr ;
}
int main()
{
genleak(); // Now also not possible, since the return value is not collected.
char* temp = genleak();
free temp; // Deallocating the resources acquired using malloc
return 0;
}
Edit:
In the posted snippet, charLeakAddr goes out of scope up on return of function call genleak(). Thus, making the resources stay there on the free way making no process to access the leaked sources. How about adding a global variable ?
char* globalVar = NULL ;
void genleak()
{
char* charLeakAddr;
charLeakAddr = (char*)malloc(sizeof(char) * 10);
// ....
globalVar = charLeakAddr ;
}
int main()
{
// .....
genleak();
free globalVar ;
}
And in genleak(), assign the value of where charLeakAddr is pointing to it. And then, the program can perform a free operation on it.

Yes, there's a way, that's called garbage collector. You can read this and this for some heads up. Basically if all your program is compiled/linked with the garbage collector, you might be able to do things like
gc.collect()
to claim back all leaked memory.

Related

asterisk: double free or corruption (fasttop)

I'm going to splice a long string using ast_malloc and ast_realloc functions.When I load this module it will occur segment fault.What's the problem? much thanks!
Asterisk's output like this:
*** glibc detected *** asterisk: double free or corruption (fasttop): 0x00007fd56c000b20 ***
======= Backtrace: =========
/lib64/libc.so.6[0x33b9675f3e]
/lib64/libc.so.6[0x33b9678dd0]
/lib64/libc.so.6[0x33b967bd60]
/lib64/libc.so.6(realloc+0x158)[0x33b967c058]
/usr/lib64/asterisk/modules/app_test2.so(func+0x25)[0x7fd5330d19c5]
/usr/lib64/asterisk/modules/app_test2.so(+0xa92)[0x7fd5330d1a92]
asterisk[0x5175d5]
asterisk(ast_load_resource+0x34)[0x51a924]
asterisk[0x4c0f80]
asterisk(ast_cli_command_full+0x162)[0x4c3ad2]
asterisk(ast_cli_command_multiple_full+0x7c)[0x4c3cfc]
asterisk[0x450b9a]
asterisk[0x5c41cb]
/lib64/libpthread.so.0[0x33b9a07aa1]
/lib64/libc.so.6(clone+0x6d)[0x33b96e8aad]
And the codes shown below:
#include "asterisk.h"
#include "asterisk/module.h"
#include "asterisk/strings.h"
#include "asterisk/json.h"
#include "asterisk/res_odbc.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define AST_MODULE "app_test"
void func(char* test, const char* src)
{
char* new_test = (char*)ast_realloc(test, strlen(test) + 32);
if ( NULL == new_test ){
ast_log(LOG_ERROR, "realloc error\n");
return;
}
test = new_test;
strcat(test, src);
}
static int load_module(void)
{
int i;
char* test;
char* src = "MingYuan";
test = (char*)ast_malloc(16);
for (i = 0; i < 6; i++) {
func(test, src);
}
ast_log(LOG_DEBUG, "\n++++\n%s\n*******\n", test);
ast_free(test);
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
return 0;
}
AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "APP_TEST",
.load = load_module,
.unload = unload_module
);
strlen(test) within func is meaningless as you haven't copied a string into test; this is likely to cause erratic behaviour. My suggestion is, after test = (char*)ast_malloc(16); you probably want something like strcpy(test, ""); or test[0] = '\0';...
As a result of pass-by-value semantics in C, these changes won't be visible to func's caller:
test = new_test;
strcat(test, src);
The caller will have an old, invalidated pointer value somewhere in a pointer variable, which is sure to cause more erratic behaviour when used again later...
My suggestion is that you develop functions so that the caller allocates memory; this won't just fix your problem, but it'll allow you to be much more flexible with how your memory is allocated, much more often.

modify fflush() that guarantee calling ungetc() twice in a row in C

I'm a C beginner, I want to call ungetc() twice in a row although I know in regular C it is not permitted. Someone told me I can modify Fflush() to do this job, however I don't know how to do it.
Here is my code, my Fflush only allow one ungetc(), I want it to allow twice.
#define altUngetc(c, fp) ((fp)->next > (fp)->buffer && (c) != EOF ? \
*--(fp)->next = (c) : EOF)
int altGetc(ALT_FILE *fp) {
if (fp->next == fp->buffer + fp->bufSize)
altFflush(fp);
return fp->flags & FILE_ATEOF ? EOF : *fp->next++;
}
int altFflush(ALT_FILE *fp) {
int res;
if (fp->fd < 0 || fp->flags & FILE_ATEOF)
return EOF;
if (fp->flags & FILE_READ) {
res = read(fp->fd, fp->buffer, BUF_SIZE);
if (res == 0)
fp->flags |= FILE_ATEOF;
fp->bufSize = res;
fp->next = fp->buffer;
}
else {
res = write(fp->fd, fp->buffer, fp->next - fp->buffer);
fp->next = fp->buffer;
}
return res < 0 ? EOF : 0;
}
As wisely mentioned in the comments, you should probably first learn to work with the rules instead of trying to break them. However, we're here to answer the question, and that means to break the rules! Take into account that neither fflush(), setbuf(), or setvbuf() would work here for different reasons.
First of all, at least four custom functions are required. One to create a "proxy buffer" relating to a file (called just after fopen()), one to destroy it (called just before fclose(), one to do the actual ungetting (replacement for ungetc(), and one to to retrieve a char from the file (replacement for fgetc(). Unfortunately, this means that performing fscanf(), fflush(), etc... on the stream will yield you bad and ugly results. You would have to rewrite all of stdio!
First of all, let's call all of our new stuff xtdio ("extended stdio"), so, first of all comes xtdio.h...
#ifndef __XTDIO_H__
#define __XTDIO_H__
#include <stdio.h>
typedef struct
{
FILE *file;
char *buffer;
size_t buffer_size;
size_t buffer_usage;
size_t buffer_tail_offset;
} XFILE;
/* I know this is not the best of API design, but I need to be
* compatible with stdio's API.
*/
XFILE *xwrap(FILE *file, size_t max_ungets);
void xunwrap(XFILE *xfile);
int xgetc(XFILE *xfile);
int xungetc(int ch, XFILE *xfile);
#endif
Then, in the interesting side of the fence, comes xtdio.c...
#include <stdlib.h>
#include <stdio.h>
#include "xtdio.h"
/* Create a XFILE wrapper, along with its respective buffer
* of 'max_ungets' size, around 'file'.
*/
XFILE *xwrap(FILE *file, size_t max_ungets)
{
XFILE *xfile = malloc(sizeof(XFILE));
if(xfile == NULL)
return NULL;
xfile->file = file;
xfile->buffer = malloc(max_ungets);
if(xfile->buffer == NULL) {
free(xfile);
return NULL;
}
xfile->buffer_size = max_ungets;
xfile->buffer_usage = 0;
xfile->buffer_tail_offset = 0;
return xfile;
}
/* Undo what 'xwrap()' did.
*/
void xunwrap(XFILE *xfile)
{
free(xfile->buffer);
free(xfile);
}
/* Check if there's something in the XFILE's
* buffer, and return it. Otherwise, fallback
* onto 'fgetc()'.
*/
int xgetc(XFILE *xfile)
{
if(xfile->buffer_usage == 0)
return fgetc(xfile->file);
if(xfile->buffer_tail_offset == 0)
xfile->buffer_tail_offset = xfile->buffer_size - 1;
else
xfile->buffer_tail_offset--;
xfile->buffer_usage--;
return xfile->buffer[xfile->buffer_tail_offset];
}
/* Here's the interesting part! If there's room in the
* buffer, it puts 'ch' in its front. Otherwise, returns
* an error.
*/
int xungetc(int ch, XFILE *xfile)
{
if(xfile->buffer_usage == xfile->buffer_size)
return EOF; //TODO: Set errno or something
xfile->buffer[xfile->buffer_tail_offset++] = (char)ch;
xfile->buffer_tail_offset %= xfile->buffer_size;
xfile->buffer_usage++;
return ch;
}
The smallish xtdio library will allow you to perform as many ungets as you pass to xwrap()'s parameter. Each XFILE has a buffer with the ungotten characters. When you xgetc(), it first checks if there's something on the buffer and retrieves it. Otherwise, it fallbacks to fgetc(). Example usage case...
#include <stdio.h>
#include <string.h>
#include "xtdio.h"
int main()
{
const char *my_string = "I just ungot this same long string in standard and compliant C! No more one-char limits on ungetc()!\n";
const size_t my_string_len = strlen(my_string);
XFILE *xtdin = xwrap(stdin, my_string_len);
if(xtdin == NULL) {
perror("xwrap");
return 1;
}
for(size_t i = my_string_len; i != 0; i--)
xungetc(my_string[i - 1], xtdin);
int ch;
while((ch = xgetc(xtdin)) != EOF)
putchar(ch);
xunwrap(xtdin);
return 0;
}
xtdio can be further improved, by adding things such as xrewrap() to extend/shrink the buffer's size.
There's an even better solution, and it is to refactor your code, and follow the conventions, so that you don't have to ungetc() twice. xtdio is just a proof of concept, but is not good code, and shall never be used in practice. This way, you won't have to deal with rewriting stdio.
If you know how to implement a int stack, you can create your own ungetc() function. Simply replace calls of ungetc() with a myungetc() (etc) that if that stack has values, pop them instead of reading from getc(). Whenever you want to un-get, simply push values on to the stack in the reverse order you read them.
An example from a recent project of mine:
/* stack.h */
#ifndef _STACK_H_
#define _STACK_H_
typedef struct {
int * vals;
int currsize;
int maxsize;
} stack;
int stack_init(stack * this, int size);
void stack_destroy(stack * this);
void push(stack * this, int val);
int pop(stack * this);
int isempty(stack * this);
int isfull(stack * this);
int size(stack * this);
int maxsize(stack * this);
#endif
/* stack.c */
#include <stdlib.h>
#include "stack.h"
#define THIS (this)
#define VALS (this->vals)
#define CURRSIZE (this->currsize)
#define MAXSIZE (this->maxsize)
int stack_init(stack * this, int size) {
VALS = malloc(sizeof(int)*size);
CURRSIZE = 0;
MAXSIZE = size;
if (!VALS) {
return 1; /* alloc fail */
}
return 0; /* successful init */
}
void stack_destroy(stack * this) {
free(VALS);
}
void push(stack * this, int val) {
if (isfull(THIS)) {
return;
}
VALS[CURRSIZE++] = val;
}
int pop(stack * this) {
if (isempty(THIS)) {
return 0;
}
return VALS[--CURRSIZE];
}
int isempty(stack * this) {
return (CURRSIZE == 0);
}
int isfull(stack * this) {
return (CURRSIZE == MAXSIZE);
}
int size(stack * this) {
return CURRSIZE;
}
int maxsize(stack * this) {
return MAXSIZE;
}
#undef THIS
#undef VALS
#undef CURRSIZE
#undef MAXSIZE
/* main.c */
#include <stdlib.h>
#include <stdio.h>
#include "stack.h"
int stgetc(FILE * stream, stack * pushed) { /* The getc() equivalent */
if (isempty(pushed)) {
return getc(stream);
} else {
return pop(pushed);
}
}
int stpush(int val, stack * pushed) { /* The ungetc() equivalent */
if (isfull(pushed)) {
return 1;
} else {
push(pushed,val);
return 0;
}
}
int main(int argc, char ** argv) {
/* startup code, etc. */
stack pushbuf; /* where the pushback will be stored */
stack_init(&pushbuf, 32) /* 32 = maximum number of ungetc calls/characters we can push */
FILE * in = fopen("/some/file","r");
/* file read */
int readchar;
while ((readchar = stgetc(in,pushbuf)) != EOF) {
/* do stuff */
stpush(readchar,pushbuf); /* oops, read too much! */
}
fclose(&in); /* close file */
stack_destroy(&pushbuf); /* clean up our buffer */
/* ... */
}
(I apologize for the wall of text but a shorter example isn't possible)
Considering you seem to be working with a file, it should be possible to fseek() backwards, although this will work for both files and stdin.

c - unsetenv() implementation, is it necessary to free memory?

As TLPI exercise 6-3 required, I made an implementation of setenv() and unsetenv() using putenv(), getenv() and via modifing environ variable directly.
Code:
// setenv() / unsetenv() impl
// TLPI exercise 6-3
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define ENV_SEP '='
extern char **environ;
// setenv() impl using putenv() & getenv()
int setenv_impl(const char * name , const char * value , int overwrite ) {
if(!overwrite && getenv(name)) { // exists & don't overwrite
return 0;
} else {
// construct the new variable
char *env_var = malloc(strlen(name) + strlen(value) + 2);
strcpy(env_var, name);
env_var[strlen(name)] = ENV_SEP;
strcpy(env_var+(strlen(name)+1), value);
int result = putenv(env_var);
if(result==0) {
return 0;
} else {
errno = result;
return -1;
}
}
}
// unsetenv() impl via modifing environ directly,
int unsetenv_impl(const char * name ) {
char **ep, **sp;
size_t len;
len = strlen(name);
for(ep = environ; *ep != NULL;) {
if(strncmp(*ep, name, len)==0 && (*ep)[len] == ENV_SEP) {
// shift all successive elements back 1 step,
for(sp=ep; *sp != NULL; sp++) {
*sp = *(sp+1);
}
} else {
ep++;
}
}
return 0;
}
// setenv_impl() test
int setenv_impl_test() {
char *key = "name";
setenv_impl(key,"Eric", 1);
printf("%s\n", getenv(key));
setenv_impl(key,"Eric2", 0);
printf("%s\n", getenv(key));
setenv_impl(key,"Eric3", 1);
printf("%s\n", getenv(key));
return 0;
}
// unsetenv_impl() test
int unsetenv_impl_test() {
char *key = "name";
setenv_impl(key,"Eric", 1);
printf("%s\n", getenv(key));
unsetenv_impl(key);
char *val = getenv(key);
printf("%s\n", val==NULL?"NULL":getenv(key));
return 0;
}
int main(int argc, void *argv[]) {
// setenv_impl_test();
unsetenv_impl_test();
return 0;
}
In my setevn_impl(), I use malloc() to allocate memory for new environment variable.
But I don't know how the memory of process's default environment allocated.
My question is:
In my unsetenv_impl() implementation, is it necesary / proper to free the memory of removed environment string by free()?
If I don't free it, will it be a problem, or it won't take much memory thus could be ignored?
Tip:
putenv() won't duplicate the string, it just make global variable environ point to the string that pass to it.
In your case it is not necessary if you don't plan to set your environment variables very frequently leading to exhaust of your memory resources.
But it would be great if you always deallocate resources after you are done with using them, be it file handles/memory/mutexs. By doing so you will not make that sort of mistake when building servers.
Some servers are expected to run 24x7. In those cases, any leak of any sort means that your server will eventually run out of that resource and hang/crash in some way. A short utility program, ya a leak isn't that bad. Any server, any leak is death. Do yourself a favor. Clean up after yourself. It's a good habit

Using malloc in function?

I am new to malloc. So I wanted to test this small code.
I'm getting the "segmentation fault error".
**EDIT: The problem was from not allocation char* name (Thanks to #Zack)
You can see what caused the problem:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct info { char *name; } fileinfo;
void mal (fileinfo **ptr)
{
if ((*ptr = (fileinfo*) malloc(3*sizeof(fileinfo))) == NULL) {
fprintf(stderr,"Memory allocating error #1\n");
exit(1);
}
//that what was causing the error - START
for (j = 0; j < 3; j += 1)
{
(*ptr)[j].name = (char*) malloc(10*sizeof(char*));
}
//that what was causing the error - END
strcpy(ptr[0]->name,"1. A\n"); //line 13
strcpy(ptr[1]->name,"2. B\n");
strcpy(ptr[2]->name,"3. C\n");
}
int main (int argc, char *argv[])
{
fileinfo *files;
int i;
mal(&files); //line 22
for (i = 0; i < 3; i += 1)
{
printf("name=%s\n",files[i].name);
}
free(files);
return 0;
}
Using valgrind:
==5751== Use of uninitialised value of size 8
==5751== at 0x4006EB: mal (mal1.c:13)
==5751== by 0x400747: main (mal1.c:22)
==5751==
==5751== Invalid write of size 4
==5751== at 0x4006EB: mal (mal1.c:13)
==5751== by 0x400747: main (mal1.c:22)
==5751== Address 0x0 is not stack'd, malloc'd or (recently) free'd
What am I doing wrong??!
Thanks in advance.
Your problem is that you need to allocate ptr[i]->name before copying to it. A pointer by itself points to some random area of memory. To use it, you must get good memory that is safe and that is what malloc and calloc, and (new in C++) all do. The example you gave is still a mess, and my correction isn't that great, but you get the idea that every pointer in C and C++ must be allocated from somewhere. And, on the flipside, once you are done with the pointer, you have to free them.
void mal (fileinfo **ptr, int count)
{
if ((*ptr = (fileinfo*) malloc(count*sizeof(fileinfo))) == NULL) {
fprintf(stderr,"Memory allocating error #1\n");
exit(1);
}
for (int i = 0; i < 3; i++) {
char buff[2];
buff[0] = 'A' + i;
buff[1] = 0;
ptr[i]->name = malloc( 10 );
strcpy(ptr[0]->name,"1. %s\n", buff);
}
}
Try with
void mal (fileinfo **ptr) {
if ((*ptr = malloc(3*sizeof(fileinfo))) == NULL) {
perror("Memory allocating error #1\n");
exit(EXIT_FAILURE);
}
if (!(ptr[0]->name = strdup("1. A\n")))
{ perror("string 1"); exit(EXIT_FAILURE);};
if (!(ptr[1]->name = strdup("2. B\n")))
{ perror("string 2"); exit(EXIT_FAILURE);};
if (!(ptr[2]->name = strdup("3. C\n")))
{ perror("string 3"); exit(EXIT_FAILURE);} ;
}
BTW, it would be better to make it a function returning a pointer, like
fileinfo* make() {
fileinfo* ptr = malloc(3*sizeof(fileinfo)));
if (!ptr) { perror("make fileinfo"); exit(EXIT_FAILURE); };
if (!(ptr[0]->name = strdup("1. A\n")))
{ perror("string 1"); exit(EXIT_FAILURE);};
if (!(ptr[1]->name = strdup("2. B\n")))
{ perror("string 2"); exit(EXIT_FAILURE);};
if (!(ptr[2]->name = strdup("3. C\n")))
{ perror("string 3"); exit(EXIT_FAILURE);} ;
return ptr;
}
Then, you need a destructor function like
void destroy(fileinfo*ptr) {
free (ptr[0]->name);
free (ptr[1]->name);
free (ptr[2]->name);
free (ptr);
}
to be called instead of your free at the end of your main
Notice that your code is very ad hoc: the number (i.e. 3) of names is completely built-in. This is wrong design. At the very least, that constant should have been named:
#define NB_FILES 3
Actually, a much better approach would be to declare your structure with a flexible array member:
typedef struct fileinfo_st {
unsigned nbfiles;
char* filenames[];
} Fileinfo;
See this for more. You could even have a variadic function to make such structures.
FIleinfo *make(int, ...);
Which you would call like
Fileinfo* ptr = make (3, "abc","def","ghijklmnop");
or you could decide that that last variadic argument is NULL
BTW, read about undefined behavior. You might be unlucky to have your program not crashing but still be very wrong. And compile with gcc -Wall -g and learn more how to use the gdb debugger and valgrind

Pointer being freed was not allocated, Abort trap: 6

I'm not proficient in C programming so please excuse me if this isn't a strong question. In the following code, I can only allocate memory to samplesVecafter obtaining the value of nsamplepts, but I need to return the vector samplesVec to the main for further use (not yet coded). However, I'm getting the following error:
Error in Terminal Window:
ImportSweeps(3497,0x7fff7b129310) malloc: * error for object 0x7fdaa0c03af8: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Abort trap: 6
I'm using Mac OS X Mavericks with the gcc compiler. Thanks for any help.
*EDITED!!! AFTER VALUABLE INPUTS FROM COMMENTATORS, THE FOLLOWING REPRESENTS A SOLUTION TO THE ORIGINAL PROBLEM (WHICH IS NO LONGER AVAILABLE) *
The following code modification seemed to solve my original questions. Thanks for the valuable inputs everyone!
/* Header Files */
#define LIBAIFF_NOCOMPAT 1 // do not use LibAiff 2 API compatibility
#include <libaiff/libaiff.h>
#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <math.h>
/* Function Declarations */
void FileSearch(char*, char*, char*, char*, char*);
int32_t *ImportSweeps(char*);
/* Main */
int main()
{
char flag1[2] = "N";
char binname[20] = "bin1"; // dummy assignment
char buildfilename[40] = "SweepR";
char skeletonpath[100] = "/Users/.../Folder name/";
int k, len;
/* Find the sweep to be imported in the directory given by filepath */
FileSearch(skeletonpath, binname, buildfilename, skeletonpath, flag1);
if (strcmp(flag1,"Y")) {
printf("No file found. End of program.\n");
} else {
len = (int) strlen(skeletonpath);
char *filepath = malloc(len);
for (k = 0; k < len; k++) {
filepath[k] = skeletonpath[k];
}
printf("File found! Filepath: %s\n", filepath);
// Proceed to import sweep
int32_t *sweepRfile = ImportSweeps(filepath);
if (sweepRfile) {
printf("Success!\n");
// Do other things with sweepRfile
free(sweepRfile);
}
free(filepath);
}
return 0;
}
/* Sub-Routines */
void FileSearch(char *dir, char *binname, char *buildfilename, char* filepath, char* flag1)
{
DIR *dp;
struct dirent *entry;
struct stat statbuf;
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"Cannot open directory: %s\n", dir);
return;
}
chdir(dir);
while((entry = readdir(dp)) != NULL) {
lstat(entry->d_name, &statbuf);
if(S_ISDIR(statbuf.st_mode)) {
/* Found a directory, but ignore . and .. */
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
continue;
strcpy(binname,entry->d_name);
strcpy(buildfilename,"SweepR");
/* Recurse at a new indent level */
FileSearch(entry->d_name, binname, buildfilename, filepath, flag1);
}
else {
sprintf(buildfilename, "%s%s.aiff", buildfilename, binname);
if (strcmp(entry->d_name,buildfilename)) {
strcpy(buildfilename,"SweepR");
} else {
sprintf(filepath, "%s%s/%s", filepath, binname, buildfilename);
strcpy(flag1,"Y");
break;
}
}
}
chdir("..");
closedir(dp);
}
int32_t *ImportSweeps(char *filepath)
{
char *filepathread = filepath;
/* Initialize files for importing */
AIFF_Ref fileref;
/* Intialize files for getting information about AIFF file */
uint64_t nSamples;
int32_t *samples = NULL;
int32_t *samplesVec = NULL;
int channels, bitsPerSample, segmentSize, ghost, nsamplepts;
double samplingRate;
/* Import Routine */
fileref = AIFF_OpenFile(filepathread, F_RDONLY) ;
if(fileref)
{
// File opened successfully. Proceed.
ghost = AIFF_GetAudioFormat(fileref, &nSamples, &channels, &samplingRate, &bitsPerSample, &segmentSize);
if (ghost < 1)
{
printf("Error getting audio format.\n");
AIFF_CloseFile(fileref); return (int32_t) 0;
}
nsamplepts = ((int) nSamples)*channels;
samples = malloc(nsamplepts * sizeof(int32_t));
samplesVec = malloc(nsamplepts * sizeof(int32_t));
ghost = AIFF_ReadSamples32Bit(fileref, samples, nsamplepts);
if (ghost) {
for (int k = 0; k < nsamplepts; k++) {
samplesVec[k] = *(samples+k);
}
}
free(samples);
AIFF_CloseFile(fileref);
}
return samplesVec;
}
So... as far as I can see... :-)
samplesVec, the return value of ImportSweeps is not initialized, if fileref is false. Automatic (== local) variables have no guarantees on its value if samplesVec are not explicitly initialized - in other words samplesVec could carry any address. If samplesVec is not NULL on luck (which on the other hand might be often the case), you try free a not allocated junk of memory, or by very bad luck an somewhere else allocated one.
If I'm correct with my guess you can easy fix this with:
int32_t *samples;
int32_t *samplesVec = NULL;
It is a good idea anyway to initialize any variable as soon as possible with some meaningful error or dummy value, if you not use it in the very next line. As pointers are horrible beasts, I always NULL them if I don't initialize them with a useful value on declaration.
Edit: Several minor small changes for a readable approximation to English. :-)
If AIFF_OpenFile fails, ImportSweeps returns an undefined value because samplesVec wasn't initialized. If that value is non-NULL, main will try to free it. You can either initialize samplesVec = NULL, or you can reorganize the code as
fileref = AIFF_OpenFile(filepathread, F_RDONLY) ;
if(!fileref) {
{
// print error message here
return NULL;
}
// File opened successfully. Proceed.
...
There are people who will insist a functon that should only have one exit -- they are poorly informed and voicing a faulty dogma handed down from others who are likewise uninformed and dogmatic. The check for error and return above is known as a guard clause. The alternate style, of indenting every time a test succeeds, yields the arrow anti-pattern that is harder to read, harder to modify, and more error prone. See http://blog.codinghorror.com/flattening-arrow-code/ and http://c2.com/cgi/wiki?ArrowAntiPattern for some discussion.

Resources