FORWARD_NULL Vs UNINIT Coverity errors in C - c

when a pointer is initialized to NULL, getting "FORWARD_NULL" coverity errors and when the NULL initialization is removed, it throws UNINIT coverity errors. The code is as below.
I am very new to coverity. If its a very basic question also, please help.
I am
1) declaring a pointer,
2) Initializing it to NULL and
3) deferring it without assigning anything to it.
This deference is an argument in a function call inside which, it will be filled in. Getting FORWARD_NULL errors for the same. Started with Coverity works, from yesterday only.
int fn1()
{
strct1 *pvarA = NULL;
if (fn2(&pvarA) != 0) // derefering NULL pointer error.
{
return 1;
}
...
/* some code */
}
int fn2(strct1 **pvarA)
{
...
/* some code */
*pvarA = varA;
/* some code */
return 0;
}
Thanks,
Preethi

In such code:
int fn1(int **ar)
{
int *a;
a = *ar;
}
The variable a is not initialized (thus UNINIT) and the variable ar is dereferenced without checking for null (thus FORWARD_NULL).
Probably this code will work:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
int fn1(int **ar)
{
int *a = NULL;
if (ar == NULL) {
fprintf(stderr, "Omg! you passed NULL as first argument to fn1 function. What to do now? Break the program flow for sure - return or abort() or exit() !");
abort();
return EXIT_FAILURE;
}
a = *ar;
return EXIT_SUCCESS;
}

This helps easily:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
strct1
{
int a;
int b;
char c;
};
int fn1()
{
strct1 *pvarA = NULL;
strct1 varA;
MEMSET(&varA, 0, sizeof (strct1));
pvarA = &varA;
if (fn2(&pvarA) != 0) // derefering NULL pointer error.
{
return 1;
}
/* some code */
}
int fn2(strct1 **pvarA)
{
/* some code */
*pvarA = varA;
/* some code */
return 0;
}

Related

Segmentation fault on double pointer dereference

The following code works fine without the statement d = *dummy; which is a double pointer dereference. However if this line is present, a segmentation fault occurs. Why so?
The code allocates and initializes memory for data structs dynamically. I was trying to simplify access to the returned pointer-to-pointer.
#include <stdlib.h>
#include <stdio.h>
typedef struct s_dummy {
char dummy_number;
} Dummy;
int mock_read_from_external_source() {
return 4;
}
int load_dummies(Dummy** dummies, int* num_of_dummies) {
*num_of_dummies = mock_read_from_external_source();
*dummies = (Dummy*) calloc(*num_of_dummies, sizeof(Dummy));
if (!dummies) {
return 1; // allocation unsuccessful
}
// Iterate dummies and assign their values...
for (int i = 0; i < *num_of_dummies; i++) {
(*dummies + i)->dummy_number = i;
}
return 0;
}
void main() {
Dummy** dummies;
Dummy* d;
int num_of_dummies = 0;
int *p_num_of_dummies = &num_of_dummies;
int err;
err = load_dummies(dummies, p_num_of_dummies);
// Segmentation fault occurs when dummies is dereferenced
d = *dummies;
if (err) {
exit(err);
}
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", (*dummies + i)->dummy_number);
}
}
Thanks in advance.
You are getting the fault because of UB, in part caused by trying to use variable objects without memory. dummies, although created as a Dummies **, has never been provided memory. At the very least, your compiler should have warned you about dummies not being initialized in this call:
err = load_dummies(dummies, p_num_of_dummies);
This is easily addressed by simply initializing the variable when it is created:
Dummy** dummies = {0}; //this initialization eliminates compile time warnings
^^^^^
Then come the run-time errors. The first is called a fatal run-time on my system, which means the OS refused to continue because of a serious problem, in this case an attempt to dereference a null pointer in this line:
dummies = (Dummy) calloc(*num_of_dummies, sizeof(Dummy));
Because you created a Dummy ** called dummies, the first step is to create memory for the pointer to pointers dummies, then create memory for the several instances of dummies[i] that will result. Only then can the members of any of them be written to.
Here is one method illustrating how memory can be created for a Dummies pointer to pointers, ( d ) and several Dummies instances ( d[i] ):
Dummy ** loadDummies(int numPointers, int numDummiesPerPointer)
{
int i;
Dummy **d = {0};
d = malloc(numPointers * sizeof(Dummy *));//Create Dummies **
if(!d) return NULL;
for(i=0;i<numPointers;i++)
{ //Now create Dummies *
d[i] = malloc(numDummiesPerPointer*sizeof(Dummy)); //random size for illustration
if(!d[i]) return NULL;
}
return d;
}
In your main function, which by the way should really be prototyped at a minimum as: int main(void){...}, this version of loadDummies could be called like this:
...
Dummies **dummies = loadDummies(4, 80);
if(!dummies) return -1;//ensure allocation of memory worked before using `dummies`.
...
After using this collection of dummies, be sure to free all of them in the reverse order they were created. Free all instances of dummies[0]-dummies[numPointers-1] first, then free the pointer to pointers, dummies
void freeDummies(Dummy **d, int numPointers)
{
int i;
for(i=0;i<numPointers;i++)
{
if(d[i]) free(d[i]);
}
if(d) free(d);
}
Called like this:
freeDummies(dummies, 4);
dummies was never assigned a value, so de-referencing will attempt to reach some random memory which is almost certainly not going to be part of your program's allocated memory. You should have assigned it to &d.
But you don't even need to do that. Just use &d once when you call the function.
Also, if you return the number of dummies allocated instead of 1/0, you can simplify your code. Something like the below (not tested):
#include <stdio.h>
int mock_read_from_external_source() {
return 10;
}
typedef struct Dummy {
int dummy_number;
} Dummy;
int load_dummies(Dummy** dummies) {
int want, i = 0;
if((want = mock_read_from_external_source()) > 0) {
*dummies = (Dummy*) calloc(want, sizeof(Dummy));
if(*dummies) {
// Iterate dummies and assign their values...
for (i = 0; i < want; i++) {
(*dummies)[i].dummy_number = i;
}
}
}
return i;
}
int main() {
Dummy* d = NULL;
int num_of_dummies = load_dummies(&d); // when &d is de-referenced, changes are reflected in d
if(num_of_dummies > 0) {
for (int i = 0; i < num_of_dummies; i++) {
printf("Dummy number: %d\n", d[i].dummy_number);
}
}
if(d) { // clean up
free(d);
}
return 0;
}

Why is there a Segmentation fault from trying to add to count and printf?

#include <stdio.h> /* the "QueueTypes.h" file, */
#include <stdlib.h> /* given above on lines 1:15, is */
#include "QueueImplementation.c"
void main(void){
Queue *que;
ItemType *num;
num = 0;
InitializeQueue(que);
int count = 0;
int check;
int i;
if(Empty(que) != 1){
count = count + 1;
}
printf("%d", count); <- segmentation fault
if(Remove(que, num) != 0){
count = count + 1; <- segmentation fault
}
These are the parts of the program that keep getting segmentation faults. Am I illegally accessing anything?
this is queueimplementation.c. When i remove the lines that are being pointed out, the program works fine and returns errors as normal.
/* ------------< begin file "QueueImplementation.c" >------------ */
#include <stdio.h> /* the "QueueTypes.h" file, */
#include <stdlib.h> /* given above on lines 1:15, is */
#include "QueueInterface.h" /* included in "QueueInterface.h" */
/* on line 3 of Program 7.4. */
void SystemError(char *errorMsg) {fprintf(stderr,errorMsg);}
void InitializeQueue(Queue *Q)
{
Q->Front = NULL;
Q->Rear = NULL;
}
/* -------------------- */
int Empty(Queue *Q)
{
return (Q->Front == NULL);
}
/* -------------------- */
int Full(Queue *Q)
{ /* we assume an already constructed queue, Q, is */
return 0; /* not full, since it could potentially grow */
} /* as a linked structure */
/* -------------------- */
int Insert(ItemType R, Queue *Q)
{
QueueNode *Temp;
/* attempt to allocate */
Temp = (QueueNode *) malloc(sizeof(QueueNode)); /* a new node */
if (Temp == NULL) { /* Temp = NULL signals allocation */
SystemError("system storage is exhausted"); /* failure */
return 0;
} else {
Temp->Item = R;
Temp->Link = NULL;
if ( Q->Rear == NULL ) {
Q->Front = Temp;
Q->Rear = Temp;
} else {
Q->Rear->Link = Temp;
Q->Rear = Temp;
}
}
return 1;
}
/* -------------------- */
int Remove(Queue *Q, ItemType *F)
{
QueueNode *Temp;
if (Q->Front == NULL) {
SystemError("attempt to remove item from empty Queue");
return 0 ;
} else {
*F = Q->Front->Item;
Temp = Q->Front;
Q->Front = Temp->Link;
free(Temp);
if (Q->Front == NULL) Q->Rear = NULL;
return 1;
}
}
/* -------------------- */
You have not initialized the pointer que when you pass it to InitializeQueue().
A better implementation might be to pass a pointer to the pointer que (i.e. a Queue**) to InitializeQueue()
void InitializeQueue(Queue **Q)
{
*Q = malloc(sizeof**Q); // set aside memory for your queue
Q->Front = NULL;
Q->Rear = NULL;
}
And call it like this
Queue *que;
InitializeQueue(&que);
If you can't change the implementation of QueueImplementation.c, then call malloc before the function call, like so:
Queue *que = malloc(sizeof*que);
InitializeQueue(que);
Or don't use heap allocation at all (my recommendation):
Queue que; // note that this is not a pointer
InitializeQueue(&que); // we have to take the address of it
Just note that with the above option, que can only be legally accessed within the function that defined it. However, this shouldn't affect you since you define it in main, so it will exist for the lifetime of your program.
As for both malloc options, remember to call free() once you finish using it.
You also fail to initialize num anywhere before you pass it to Remove(). You should fix it similarly.
You might consider using a debugger such as valgrind. Segmentation faults don't always occur (if they occur at all) at the same line of code that caused it and can be unreliable as a way of error checking.
P.S. It's sufficient to use if (Empty(que)) instead of if (Empty(que) != 1) because expressions are "true" when they evaluate to a non-zero integer. It's arguably safer because all "true" values don't have to be 1.
P.P.S. Don't #include .c files. Include the .h file and compile the .c file with your main program. If you're using gcc, then
gcc myprogram.c QueueImplementation.c
Other compilers use the same syntax (there's probably an exception somewhere but I haven't encountered it).
In C, when you just declare a pointer Queue *, it doesn't magically point to a new "valid" instance of Queue. In fact, it points to a random location in memory which most likely doesn't contain anything that makes sense to you.
To simplify, in your code you are doing:
Get me a pointer que, I don't care where it points to.
Put { NULL, NULL } to where the pointer points to.
So you are writing { NULL, NULL } to a random part of system memory.
This is not how you do it. Look at the example Luddite has provided.
And additionally, please read this article to understand what is going on here:
https://www.cs.cf.ac.uk/Dave/C/node10.html

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.

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.

c - mixing assignment and free() in a condition?

typedef char* string;
int func1(string s);
char* func2(); // returns a new memory/
if(func1(func2()) == 4)
{
// code
}
Assuming func2() is only needed in the condition. Since i need to free newly allocated memory, how can i free it up within the same line(i.e. with the same condition or paranthesis) ? My motiviton for this is to keep the code clean.
EDIT 1.
Yes it is a c question. The use of "string" type was error on my part as i have always typedef it to char*. Sorry for the confusion.
To do this cleanly, make a new function that does the work in a clear manner:
static int func3()
{
char *s = func2();
int result = func1(s);
free(s);
return result;
}
…
if (func3() == 4)
…
(Presumably, there is some assurance that func2 successfully allocates memory. If not, you must test its return value.)
Free it in the same line with no new function definitions:
int result;
char *temp;
/* comma operator: evaluate these 4 expressions left-to-right,
and the value is the value of the last expression */
if(temp = func2(), result = (func1(temp) == 4), free(temp), result)
{
/* Do things */
}
Cleaner code:
int func3(void)
{
char *temp;
int result;
temp = func2();
result = func1(temp);
free(temp);
return result;
}
/* ... */
if(func3() == 4)
{
/* do things */
}
Here is a solution using a functional approach:
int apply_free(int (*f1)(char*), char * (*f2)()) {
char *s = f2();
if (s != NULL) {
int result = f1(s);
free(s);
return result;
}
else {
return -1; /* or any meaningful value if f2 returned a NULL pointer */
}
}
if (apply_free(func1, func2) == 4)
{
// code
}
This assumes your various cases will have the same type signature.

Resources