I am currently having exceptional difficulty with CUDA programming--more specifically, in copying and reading an array which the device sends back to the host. When I attempt to read the data which I am supposed to have returned to me, all I get is junk data. Could anyone take a look at my code snippets and tell me what I'm doing wrong? Thank you very much!
struct intss {
u_int32_t one;
u_int32_t two;
};
int main()
{
int block_size = 3;
int grid_size = 1;
intss *device_fb = 0;
intss *host_fb = 0;
int num_bytes_fb = (block_size*grid_size)*sizeof(intss);
host_fb = (intss*)malloc(num_bytes_fb);
cudaMalloc((void **)&device_fb, num_bytes_fb);
....
render2<<<block_size,grid_size>>>(device_fb, device_pixelspercore, samples, obj_list_flat_dev, numOpsPerCore, lnumdev, camdev, lightsdev, uranddev, iranddev);
....
cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost);
printf("output %d ", host_fb[0].one);
printf("output %d ", host_fb[1].one);
printf("output %d ", host_fb[2].one);
//Note that I'm only looking at elements the 3 elements 0-2 from host_fb. I am doing this because block_size*grid_size = 3. Is this wrong?
cudaFree(device_fb);
free(host_fb);
}
__global__ void render2(intss *device_fb, struct parallelPixels *pixelsPerCore, int samples, double *obj_list_flat_dev, int numOpsPerCore, int lnumdev, struct camera camdev, struct vec3 *lightsdev, struct vec3 *uranddev, int *iranddev) //SPECIFY ARGUMENTS!!!
{
int index = blockIdx.x * blockDim.x + threadIdx.x; //DETERMINING INDEX BASED ON WHICH THREAD IS CURRENTLY RUNNING
....
//computing data...
device_fb[index].one = (((u_int32_t)(MIN(r, 1.0) * 255.0) & 0xff) << RSHIFT |
((u_int32_t)(MIN(g, 1.0) * 255.0) & 0xff) << GSHIFT |
((u_int32_t)(MIN(b, 1.0) * 255.0) & 0xff) << BSHIFT);
}
EDIT:
Thanks to a suggestion, I have implemented the CudaErrorCheck function in my program, and there seems to be a pattern in which functions are giving me errors.
In my program, I have a bunch of global host arrays(obj_list, lights, urand, irand). Whenever I attempt to use cudaMemCpy to copy these host arrays to device arrays, I receive the following error:
"Cuda error in file 'cudatrace.cu' in line x : invalid argument."
obj_list and lights are filled in the following function, load_scene():
void load_scene(FILE *fp) {
char line[256], *ptr, type;
obj_list = (sphere *)malloc(sizeof(struct sphere));
obj_list->next = 0;
objCounter = 0;
while((ptr = fgets(line, 256, fp))) {
int i;
struct vec3 pos, col;
double rad, spow, refl;
while(*ptr == ' ' || *ptr == '\t') ptr++;
if(*ptr == '#' || *ptr == '\n') continue;
if(!(ptr = strtok(line, DELIM))) continue;
type = *ptr;
for(i=0; i<3; i++) {
if(!(ptr = strtok(0, DELIM))) break;
*((double*)&pos.x + i) = atof(ptr);
}
if(type == 'l') {
lights[lnum++] = pos;
continue;
}
if(!(ptr = strtok(0, DELIM))) continue;
rad = atof(ptr);
for(i=0; i<3; i++) {
if(!(ptr = strtok(0, DELIM))) break;
*((double*)&col.x + i) = atof(ptr);
}
if(type == 'c') {
cam.pos = pos;
cam.targ = col;
cam.fov = rad;
continue;
}
if(!(ptr = strtok(0, DELIM))) continue;
spow = atof(ptr);
if(!(ptr = strtok(0, DELIM))) continue;
refl = atof(ptr);
if(type == 's') {
objCounter++;
struct sphere *sph = (sphere *)malloc(sizeof(*sph));
sph->next = obj_list->next;
obj_list->next = sph;
sph->pos = pos;
sph->rad = rad;
sph->mat.col = col;
sph->mat.spow = spow;
sph->mat.refl = refl;
} else {
fprintf(stderr, "unknown type: %c\n", type);
}
}
}
urand and irand are filled in main as follows:
/* initialize the random number tables for the jitter */
for(i=0; i<NRAN; i++) urand[i].x = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) urand[i].y = (double)rand() / RAND_MAX - 0.5;
for(i=0; i<NRAN; i++) irand[i] = (int)(NRAN * ((double)rand() / RAND_MAX));
I don't think the invalid argument could be caused by the device array, since the cudaMalloc call creating the device array before the cudaMemcpy call did not have a CudaError message. For example, in the following lines of code:
cudaErrorCheck(cudaMalloc((void **)&lightsdev, MAX_LIGHTS*sizeof(struct vec3)) );
cudaErrorCheck( cudaMemcpy(&lightsdev, &lights, sizeof(struct vec3) * MAX_LIGHTS, cudaMemcpyHostToDevice) );
cudaMalloc did not produce an error, but cudaMemcpy did.
If I have not provided enough information on my code, I have pasted the entire code to: http://pastebin.com/UgzABPgH
(Note that in the pastebin version, I took out the CudaErrorCheck functions on the CudaMemcpy's which were producing the errors.)
Thank you very much!
EDIT:
Actually, I just tried to see what would happen if urand and irand were not global, and if they were initialized alongside the device arrays uranddev and iranddev. I'm still getting the same "invalid argument" error, so the whether or not a variable is global must not relate to the problem.
It is absolutely impossible to say anything when you have posted incomplete, uncompilable code with no proper description of the actual problem. You will get better answers by asking better questions on StackOverflow.
Having said that. the most likely problem isn't that the data is not being copied to or from the device, it is that the kernel itself is not running. Every CUDA runtime API call returns a status code, and you should be checking all of them. You can define an error checking macro like this one:
#include <stdio.h>
#define cudaErrorCheck(call) { cudaAssert(call,__FILE__,__LINE__) }
void cudaAssert(const cudaError err, const char *file, const int line)
{
if( cudaSuccess != err) {
fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n",
file, line, cudaGetErrorString(err) );
exit(1);
}
}
and wrap every API call in it, like this:
cudaErrorCheck( cudaMemcpy(host_fb, device_fb, num_bytes_fb, cudaMemcpyDeviceToHost) );
For the kernel launch, itself you can check for a launch failure or runtime error like this:
kernel<<<....>>>();
cudaErrorCheck( cudaPeekAtLastError() ); // Checks for launch error
cudaErrorCheck( cudaThreadSynchronize() ); // Checks for execution error
My suggestion is add thorough error checking to your code and then come back and edit your question with the results you get. Then someone might be able to offer concrete suggestions about what is happening.
I think you're not using the <<< >>> syntax correctly.
Here's a kernel invocation from the CUDA Programming Guide:
MatAdd<<<numBlocks, threadsPerBlock>>>(A, B, C);
which would mean that the grid size should go first.
There's also a limitation on the maximum size for the arguments to a kernel. See this. If you go above it, I'm not sure whether the compiler complains or just goes on to do nasty things.
If I remove all the arguments but device_fb, and just set device_fb[index]=index in the kernel, I can read the values successfully.
Related
--Important Edit--
Thanks for the tip on compiling with -fsanitize=address -g, it allowed me to track down the problem. I'm almost done and I've isolated the issue (which happens near the top of the cleanup function). To simplify things, why does the following (when compiled with the above flags) fail?
#include <stdio.h>
#include <stdlib.h>
struct pair {
char *left;
char *right;
};
int main() {
struct pair *pairs = malloc(100 * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
printf("%i\n", x);
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
}
return 0;
}
After printing 0-7 on new lines, I get ==9803==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61b000000788 at pc 0x00010cb90d88 bp 0x7ffee306fa90 sp 0x7ffee306fa88...Address 0x61b000000788 is a wild pointer.
--Original Question--
I've been working on a brainfuck interpreter in C, but I keep inconsistently getting a segfault. While trying to debug this for a day, I've done many things which, rather than catching where the problem is, simply cause it not to happen. I think at this point I'm encountering undefined behavior, but after rereading my code multiple times I don't see where it could be happening. All of these things cause the program to work as intended:
Printing a variable amount of characters between the bottom of the function body of cleanup and the top of the function body of execute (including inside the main function), though this isn't always consistent
Compiling with the -g flag for debugging
At the top of the execute function
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
changing 30000 to 1000 and 29999 to 999
I've read the documentation on malloc, realloc, and calloc, and browsed for other answers, and I still can't tell the problem. As far as I can tell, I have no memory leaks (even when I realloc a struct pair*, the memory at the pointers within each struct is not leaked because it is within the char *program block) or other issues. That's why I would provide the minimal answer to reproduce the problem, but I'm beginning to doubt that removing seemingly unrelated parts of my source code will have no effect on it (though I have stripped down my code a lot still).
I'm using Mac OS X 10.14, bash "gcc -o brainfc brainfc.c" OR "clang -o brainfc brainfc.c" to compile, "brainfc mandelbrot.b" to run program.
The mandelbrot.b file can be found here: http://esoteric.sange.fi/brainfuck/utils/mandelbrot/mandelbrot.b
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *program = NULL;
struct pair {
char *left;
char *right;
};
//Reads into global variable program from file
void fileinput(char *filename) {
FILE *fp;
fp = fopen(filename, "rb");
if (fp) {
size_t inputlen = 0;
fseek(fp, 0, SEEK_END);
int filesize = ftell(fp);
rewind(fp);
program = malloc(filesize + 1);
fread(program, filesize, 1, fp);
*(program + filesize) = 0;
fclose(fp);
}
}
//Removes unwanted characters from program, as well as compiling lookup table of pairs
//This happens in a single sweep through the program for efficiency,
//though again this problem might not occur if I optimized for readability
struct pair* cleanup() {
int pairsize = 200;
struct pair *pairs = calloc(pairsize, sizeof(*pairs));
char *src, *dest;
struct pair *buildptr = pairs;
int bracketlevel = 0;
for (src = dest = program; *src; dest += (strchr("<>+-[].,", *src++) != NULL)) {
*dest = *src;
if (*dest == '[') {
bracketlevel++;
while (buildptr->left) {
if (buildptr == pairs + (pairsize - 1) * sizeof(*pairs)) {
pairsize += 100;
pairs = realloc(pairs, pairsize * sizeof(*pairs));
for (int x = 0; x < 100; x++) {
buildptr += sizeof(*pairs);
buildptr->left = buildptr->right = NULL;
}
buildptr -= sizeof(*pairs) * 100;
}
buildptr += sizeof(*pairs);
}
buildptr->left = dest;
} else if (*dest == ']') {
bracketlevel--;
if (bracketlevel < 0) {
return NULL;
}
while (buildptr->right) {
buildptr -= sizeof(*pairs);
}
buildptr->right = dest;
}
}
if (bracketlevel != 0) {
return NULL;
}
*dest = 0;
program = realloc(program, strlen(program) + 1);
return pairs;
}
//Executes program
int execute(struct pair *pairs) {
unsigned char *pointer = (unsigned char*) calloc(30000, 1);
unsigned char *leftbound = pointer, *rightbound = pointer;
rightbound += 29999;
for (char *pc = program; *pc; pc++) {
switch (*pc) {
case '<':
if (pointer == leftbound) return 1;
pointer--;
break;
case '>':
if (pointer == rightbound) return 1;
pointer++;
break;
case '+':
(*pointer)++;
break;
case '-':
(*pointer)--;
break;
case '[':
while (pairs->left != pc) pairs += sizeof(*pairs);
if (!(*pointer)) pc = pairs->right;
break;
case ']':
while (pairs->right != pc) pairs -= sizeof(*pairs);
if (*pointer) pc = pairs->left;
break;
case '.':
printf("%c", *pointer);
break;
case ',':
printf("Inputting 10 (for now)\n");
*pointer = 10;
break;
}
}
return 0;
}
//Parses command line arguments, calls each function in order
int main(int argc, char *argv[]) {
if (argc > 0) {
char *filepath = argv[1];
fileinput(filepath);
}
if (program == NULL) {
printf("Error: File not found\n");
return 3;
}
struct pair *pairs = cleanup();
if (pairs == NULL) {
printf("Error: Invalid program\n");
return 4;
}
int execstatus = execute(pairs);
switch (execstatus) {
case 1:
printf("\nError: Pointer out-of-bounds\n");
return 1;
case 2:
printf("\nError: Byte overflow\n");
return 2;
default:
return 0;
}
}
Any help would be greatly appreciated.
pairs += sizeof(*pairs);
Pointer arithmetic in C is always in units of the type pointed to - here, it's in units of struct pairs. So if you want pairs to point to the next struct pair in the array, add 1. (The compiler will internally translate this into adding the appropriate number of bytes, or however pointers happen to work on your system.) This line should be pairs += 1; or pairs++; or ++pairs; according to your taste.
As it stands, if sizeof(*pairs) happens to be, say, 16 on your system, you are skipping past 15 more struct pairs every time you iterate. You will end up accessing the 0th, 16th, 32nd, ... 1584th struct pair in the array. Since it only contains 100, obviously most of these will be out of bounds. Hence your segfault.
As previously mentioned the usage of pointers is a bit messed up.
Instead of
pairs->left = pairs->right = NULL;
pairs += sizeof(*pairs);
Use
pairs[x].left = pairs[x].right = NULL;
As a bonus you have pairs still intact to do the clean up
i use this part of code to read float value from OSC message on my microcontroller. However i get "dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]" error and no value is showed on printf. Is there any workaround for this one? marker is in struct as:
char *marker; // the current read head
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
return *((float *) (&i)); <---- this line of code does the error
}
EDIT :
So, i recieve data from microcontrollers internet chip over udp using function:
datasize_t recvfrom(uint8_t sn, uint8_t * buf, datasize_t len, uint8_t * addr, uint16_t *port, uint8_t *addrlen) //<- general
then i run another function to parse osc message:
tosc_parseMessage(&A, (char*) buf, received_size); //<- how i wrote parameters
where A is structure:
typedef struct tosc_message {
char *format; // a pointer to the format field
char *marker; // the current read head
char *buffer; // the original message data (also points to the address)
uint32_t len; // length of the buffer data
} tosc_message;
and tosc_parseMessage is:
int tosc_parseMessage(tosc_message *o, char *buffer, const int len) {
// NOTE(mhroth): if there's a comma in the address, that's weird
int i = 0;
while (buffer[i] != '\0') ++i; // find the null-terimated address
while (buffer[i] != ',') ++i; // find the comma which starts the format string
if (i >= len) return -1; // error while looking for format string
// format string is null terminated
o->format = buffer + i + 1; // format starts after comma
while (i < len && buffer[i] != '\0') ++i;
if (i == len) return -2; // format string not null terminated
i = (i + 4) & ~0x3; // advance to the next multiple of 4 after trailing '\0'
o->marker = buffer + i;
o->buffer = buffer;
o->len = len;
return 0;
}
and then i print that out with :
void tosc_printMessage(tosc_message *osc) {
printf("[%i bytes] %s %s",
osc->len, // the number of bytes in the OSC message
tosc_getAddress(osc), // the OSC address string, e.g. "/button1"
tosc_getFormat(osc)); // the OSC format string, e.g. "f"
for (int i = 0; osc->format[i] != '\0'; i++) {
switch (osc->format[i]) {
case 'f': printf(" %g", tosc_getNextFloat(osc)); break;
case 'd': printf(" %g", tosc_getNextDouble(osc)); break;
case 'i': printf(" %d", tosc_getNextInt32(osc)); break;
default: printf(" Unknown format: '%c'", osc->format[i]); break;
}
}
printf("\n");
}
where my problem is in function:
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
return *((float *) (&i)); <---- this line of code does the error
}
I hope this gives you better view on problem... Im not skilled programmer so i appreciate any help. Full code for this "library" could be found here https://github.com/mhroth/tinyosc , Im just trying to implement that in my microcontroller
float tosc_getNextFloat(tosc_message *o) {
// convert from big-endian (network btye order)
const uint32_t i = ntohl(*((uint32_t *) o->marker));
o->marker += 4;
float tmp = 0;
memcpy((void *)&tmp, (void *)&i, sizeof(uint32_t));
return tmp;
}
If type punning is required, it is better to use a compiler that is configured to support it (which on some non-commercially-designed compilers, but not commercially-designed ones, means using -fno-strict-aliasing) than to jump through hoops to accommodate compiler writers that refuse to recognize type punning via pointers that are visibly freshly derived.
C implementations are sometimes used for purposes where type punning is useful, and sometimes for purposes where it isn't. The authors of the Standard recognized that compiler writers should know more about their individual customers' needs than the Committee possibly could, and thus allowed implementations to support whatever combinations of constructs would best fit their customers' needs. Somehow a myth has emerged that Standard characterizes as "broken" programs which relies upon implementations to process them "In a documented fashion characteristic of the environment", but any such reading directly contradicts the stated intentions of the Standard's authors.
After all it wasnt code problem. Yes, i still get that warning ( BUT CODE WORKS ). Actual problem was in IDE. In linker setting inside builder settings this was needed to be added : -u _printf_float . That took like month of my life figuring out what's happening. Thank you all for answering
I'm trying to write out the memory that I get from a video 4 linux 2 example program. However, it's not working. I'm getting a segmentation fault when trying to access the pointer. I hope this isn't a stupid mistake because I've spent a couple of days on it. Here is the code: (It's not formatted because there were too many conflicts with html.)
My computer is using the mmap branch of execution. It seg faults in writeFile() at this line:
mRGB = mScreen->pixels[pixel];
I'm using the v4l2 example code found here
http://linuxtv.org/downloads/v4l-dvb-apis/capture-example.html
Here are the changes I made:
at line 497 I changed
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB332;
fmt.fmt.pix.field = V4L2_FIELD_NONE;
I also added a line to main(...) at around line 704 somewhere.
close_device();
writeFile();
fprintf(stderr, "\n");
and I've inserted a writeFile() method specified below:
typedef struct Screen {
unsigned char pixels[640*480];
} Screen;
static void writeFile() {
const int dimx = 640, dimy = 480;
int mNumPixels = dimx * dimy;
Screen *mScreen;
int i, pixel;
FILE *file = fopen("output","w");
if (file == NULL) return;
/* shift the bits around */
(void)fprintf(file, "P6\n%d %d\n255\n", dimx, dimy);
for (i = 1; i < n_buffers; i++) {
mScreen = buffers[i].start;
printf("\npointer to mScreen is: %p\n", mScreen);
for (pixel = 0; pixel < 640*480; pixel++) {
static unsigned char color[3];
unsigned char mRGB = 0;
printf("%d:%x\n", pixel, mRGB);
fflush(stdout);
mRGB = mScreen->pixels[pixel];
color[0] = (mRGB & 0xE0) >> 5;
color[1] = (mRGB & 0x1D) >> 2;
color[2] = mRGB & 0x03;
fwrite(color, sizeof(unsigned char)*3, 1, file);
}
}
fclose(file);
}
uninit_device() of the sample code modifies the available memory such that the pointer isn't available any more. The writeFile() method must be called before this method/function.
I am working on a c code that holds a structure that hosts some values which I call range.
My purpose is to use this so called range dynamically (holding different amount of data at every execution). I am now provisionally using the # define comp instead. This so called range gets updated every time I call my update_range though the use of s1 structure (and memory allocations).
What I found weird is that when I introduced a "show_range" function to output the actual values inside/outside the update function I realized that I loose the first two values.
Here is the code.
Any suggestions on that?
Thanks in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <errno.h>
#include <string.h>
#include <complex.h>
#define comp 1024
// struct holding a complex-valued range
struct range {
int dimensions; /* number of dimensions */
int* size; /* array holding number of points per dimension */
complex double* values; /* array holding complex valued */
int components; /* number of components that will change on any execution*/
};
// parameters to use in function
struct s1 {
int tag;
struct range* range;
};
int update_range(struct s1* arg);
int show_range(struct range* argrange, char* message);
int copy_range(struct range* in, struct range* out);
int main(void) {
int ret = 0;
struct s1 s1;
s1.tag = 0;
s1.range = malloc(sizeof(struct range));
update_range(&s1);
show_range(s1.range, "s1.range inside main function");
return ret;
}
////////////////////////////////////////////
int update_range(struct s1* arg) {
int ret = 0;
int i;
struct range range;
range.dimensions = 1;
range.size = malloc(range.dimensions * sizeof(int));
range.components = comp;
range.size[0] = range.components; // unidimensional case
range.values = malloc(range.components * sizeof(complex double));
for (i = 0; i < range.components; i++) {
range.values[i] = (i + 1) + I * (i + 1);
}
show_range(&range, "range inside update_range function");
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
copy_range(&range, arg->range);
show_range(arg->range, "arg->range inside update_range function");
if (range.size)
free(range.size);
range.size = NULL;
if (range.values)
free(range.values);
range.values = NULL;
return ret;
}
////////////////////////////////////////////
// Show parameters (10 first values)
int show_range(struct range* argrange, char* message) {
int ret = 0;
vint i;
printf(" ******************************\n");
printf(" range in %s \n", message);
printf(" arg.dimensions=%d \n", argrange->dimensions);
printf(" arg.size[0]=%d \n", argrange->size[0]);
printf(" argrange.components=%d \n", argrange->components);
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
printf("\n");
return ret;
}
////////////////////////////////////////////
// copy range
int copy_range(struct range* in, struct range* out) {
int ret = 0;
if (in == NULL) {
fprintf(stderr, "error: in points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
if (out == NULL) {
fprintf(stderr, "error: out points to NULL (%s:%d)\n", __FILE__,
__LINE__);
ret = -1;
goto cleanup;
}
out->dimensions = in->dimensions;
out->size = in->size;
out->values = in->values;
out->components = in->components;
cleanup:
return ret;
}
Your copy_range function is broken, because it copy only pointer to size and values and not the memory. After you call free(range.size); and free(range.values); you are deleting mamory also from original object but without setting its pointers back to NULL.
After calling update_range, s1.range has non NULL pointers in size and values, but they are pointing to deleted memory.
You are experiencing undefined behaviour (UB) due to accessing freed memory. Your copy_range() function only does a shallow copy of the two pointer fields so when you run free(range->size) you make arg->range->size invalid.
You should make copy_range() a deep copy by allocating and copying the pointer contents like:
out->size = malloc(in->dimensions * sizeof(int));
memcpy(out->size, in->size, in->dimensions * sizeof(int));
out->values = malloc(in->components * sizeof(complex double));
memcpy(out->values , in->values, in->components * sizeof(complex double));
There are not 10 items to print, so the lines:
printf(" first 10 {Re} values: \n");
for (i = 0; i < 10; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
Will be printing from random memory.
a much better method would be:
printf(" first %d {Re} values: \n", min(argrange.components,10));
for (i = 0; i < argrange.components; i++) {
printf(" argrange.values[%d]=%f\n", i, creal(argrange->values[i]));
}
The above is just one of many problems with the code.
I would suggest executing the code using a debugger to get the full story.
as it is, the code has some massive memory leaks due mostly
to overlaying malloc'd memory pointers.
for instance as in the following:
arg->range->size =
malloc(range.dimensions * sizeof(int)); // size was unknown before
arg->range->values =
malloc(comp * sizeof(complex double)); // amount of values was unknown
I have written a piece of code that attempts to search a directory and its subfolders for two AIFF files and using the LibAIFF library to import and then perform some processing operations on them.
Part 1: Searching the directory for the files
For this part of the program, I need to look for the files (which can be thought of as identical AIFF files except for a difference in their filenames) with known names (for example SineSweepA.aiff and SineSweepB.aiff) and then construct the absolute path to it (the length of which I am unaware of (since my program needs to work on different computers where the AIFFs can be located within different subfolders within a MainDirectory - see code below) but know will be less than 200 characters in length). I am able to do this successfully and consistently using the following piece of code:
void file_search(char* parentDir, char* subFolder, char* filenamePrefix, char* tempString, char* tempFilepath, int* foundFlag, int* level);
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag);
int main()
{
...
char MainDirectory[200] = "/Users/rrr/Documents/Foldername1/";
char tempFilepath[200], tempFilepathR[200], parentDir[200], filenamePrefix[200], subFolder[200], tempString[200];
int level = 0, foundFlag = 0;
int numChannels = 0;
int bitDepth;
int segmentSize;
int importFlag = 0;
int32_t *sweepRfile = NULL;
uint64_t numSamples = 0, numSamplesR = 0;
unsigned long templen;
double samplingRate = 0.0;
char *sweepFilepath = NULL, *sweepFilepathR = NULL; // Allocated to specific size later
strcpy(parentDir, MainDirectory);
strcat(parentDir, "SubFolderName1/");
strcpy(tempFilepathR, parentDir);
strcpy(filenamePrefix, "KnownFilenamePrefix1");
// file_search() searches for a specific file with a known name and constructs the absolute path to the file and stores it in tempFilepathR. The function is shown further below.
file_search(parentDir, subFolder, filenamePrefix, tempString, tempFilepath, &foundFlag, &level);
if (foundFlag)
{
sprintf(tempFilepath, "%s%s/KnownFilenamePrefix1%s.aiff", parentDir, subFolder, subFolder);
sprintf(tempFilepathR, "%s%s/KnownFilenamePrefix2%s.aiff", parentDir, subFolder, subFolder);
}
...
(to be continued in Part 2 of my question below)
}
void file_search(char* dir, char* subfolder, char* fileprefix, char* filename, char* filepath, int*flag, int* level)
{
DIR *dp;
struct dirent *entry; // entry is a pointer to the structure "dirent" defined in <dirent.h>
struct stat statbuf; // the structure "stat" is defined in <stat.h>
if((dp = opendir(dir)) == NULL) {
fprintf(stderr,"Cannot open directory: %s\n", dir);
return;
}
chdir(dir); // this sets the working directory to the string pointed to by "dir"
while((entry = readdir(dp)) != NULL)
{
lstat(entry->d_name, &statbuf);
if(S_ISDIR(statbuf.st_mode)) // Tests for a directory
{
// Found a directory
if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0)
{
// Ignore . and ..
continue;
}
if(level[0] < 1)
{
// Proceed down one level and search again
strcpy(subfolder,entry->d_name);
level[0] = level[0] + 1;
// Recursive function call
file_search(entry->d_name, subfolder, fileprefix, filename, filepath, postfilepath, flag, level);
level[0] = level[0] - 1;
if(flag[0] == 1)
{
// Exit loop if a file was found at a lower level
break;
}
}
}
else
{
sprintf(filename, "%s%s.aiff", fileprefix, subfolder);
if(strcmp(entry->d_name,filename) == 0)
{
// File found. Construct absolute path to file
sprintf(filepath, "%s%s/%s", filepath, subfolder, filename); // Pass filepath outside
flag[0] = 1; //Appropriate file found
break;
}
}
}
chdir("..");
closedir(dp);
}
So by using the above code, I am able to successfully search for two AIFF files with given filenames by searching through subfolders with a known MainDirectory, construct their absolute paths and store them in tempFilepath and tempFilepathR. The next step is to import these two files and this is where I run into a problem.
Part 2: Importing the files
The problem I run into is as follows: I implemented the LibAIFF library to import the files. The issue is that if I run the program, say N times, then on some of the runs, the first file gets imported but not the second, on other runs the second gets imported but not the first (note that if the first doesn't get imported, the program stops). Before I explain the error, please know that there is no issue with the AIFF files, for the sake of this problem you can assume they are identical and that even their absolute paths and filenames are identical except one has a suffix A.aiff and the other B.aiff. These file paths are stored as strings in identically defined variables (tempFilepath and tempFilepathR).
Here is the rest of the necessary part of my code continued from above
int main()
{
// Continued from above
...
// Copy over exact file paths (I had to do this because the function AIFF_OpenFile which is part of the LibAIFF library and shown below refused to accept a statically allocated char variable such as tempFilepath)
templen = strlen(tempFilepathR); // tempFilepath and tempFilepathR always have the same length
sweepFilepath = malloc(templen + 1);
strcpy(sweepFilepath, tempFilepath);
// Proceed to import the FIRST AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepath, &numSamples, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepath);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepath);
}
// Now for the SECOND AIFF (I can overwrite a lot of the variables used for the first AIFF because I don't need them)
sweepFilepathR = malloc(templen + 1); // templen is assigned above
strcpy(sweepFilepathR, tempFilepathR);
// Proceed to import the SECOND AIFF (returned to sweepRfile from import_sweeps())
sweepRfile = import_sweeps(sweepFilepathR, &numSamplesR, &numChannels, &samplingRate, &bitDepth, &segmentSize, &importFlag);
if (importFlag) // The import was successful
{
free(sweepFilepathR);
// Do some processing with the successfully imported AIFF
free(sweepRfile);
}
else // The import was unsuccessful and sweepRfile (which is usually malloc'ed in the import_sweeps() function is not malloc'ed
{
free(sweepFilepathR);
}
...
// Rest of code in main is irrelevant because it doesn't even get there.
}
The break always occurs within the import_sweeps() function (sometimes for the first AIFF and sometimes for the second). The function is shown below
int32_t *import_sweeps(char* sweepFilepath, uint64_t* numSamples, int* numChannels, double* samplingRate, int* bitDepth, int* segmentSize, int* importFlag)
{
// Initialize files for importing */
AIFF_Ref fileref;
// Import Routine */
fileref = AIFF_OpenFile(sweepFilepath, F_RDONLY);
if(fileref)
{
// File opened successfully. Proceed to intialize files for getting information about AIFF file
uint64_t nSamples;
int nSamplePts, channels, bitsPerSample, segSize, temp;
double smpr;
// Get AIFF file format details
temp = AIFF_GetAudioFormat(fileref, &nSamples, &channels, &smpr, &bitsPerSample, &segSize);
if (temp < 1) {
fprintf(stderr,"Error getting audio format.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
else
{
numSamples[0] = nSamples;
samplingRate[0] = smpr;
numChannels[0] = channels;
bitDepth[0] = bitsPerSample;
segmentSize[0] = segSize;
nSamplePts = ((int) nSamples)*channels;
int32_t *samples = malloc((nSamplePts+1) * sizeof(int32_t));
// Read AIFF
temp = AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);
if (temp != -1)
{
AIFF_CloseFile(fileref);
importFlag[0] = 1;
return samples;
}
else
{
fprintf(stderr,"Unable to read AIFF.\n");
AIFF_CloseFile(fileref);
return (int32_t) 0;
}
}
}
else
{
fprintf(stderr,"Unable to open AIFF file.\n");
}
return (int32_t) 0;
}
Inside import_sweeps() above, the AIFF file is ALWAYS successfully read by calling the function AIFF_ReadSamples32Bit(fileref, samples, nSamplePts);. Therefore, the temp value is never -1. Whenever an error (as described above and I will give the actual error message below) happens, it ALWAYS occurs when it tries to call AIFF_CloseFile(fileref);.
Shown below are the functions AIFF_ReadSamples32Bit and AIFF_CloseFile as defined in the LibAIFF library.
int AIFF_ReadSamples32Bit(AIFF_Ref r, int32_t * samples, int nSamplePoints)
{
int n = nSamplePoints;
void *buffer;
int i, j;
size_t h;
size_t len;
int segmentSize;
int32_t *dwords;
int16_t *words;
int8_t *sbytes;
uint8_t *inbytes;
uint8_t *outbytes;
uint8_t x, y, z;
if (!r || !(r->flags & F_RDONLY))
return -1;
if (n % (r->nChannels) != 0)
return 0;
if (n < 1 || r->segmentSize == 0) {
if (r->buffer) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
}
return -1;
}
segmentSize = r->segmentSize;
len = (size_t) n * segmentSize;
if ((r->buflen) < len) {
if (r->buffer)
free(r->buffer);
r->buffer = malloc(len);
if (!(r->buffer)) {
return -1;
}
r->buflen = len;
}
buffer = r->buffer;
h = AIFF_ReadSamples(r, buffer, len);
if (h < (size_t) segmentSize) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return 0;
}
n = (int) h;
if (n % segmentSize != 0) {
free(r->buffer);
r->buffer = NULL;
r->buflen = 0;
return -1;
}
n /= segmentSize;
switch (segmentSize) {
case 4:
dwords = (int32_t *) buffer;
for (i = 0; i < n; ++i)
samples[i] = dwords[i];
break;
case 3:
inbytes = (uint8_t *) buffer;
outbytes = (uint8_t *) samples;
n <<= 2; /* n *= 4 */
j = 0;
for (i = 0; i < n; i += 4) {
x = inbytes[j++];
y = inbytes[j++];
z = inbytes[j++];
#ifdef WORDS_BIGENDIAN
outbytes[i] = x;
outbytes[i + 1] = y;
outbytes[i + 2] = z;
outbytes[i + 3] = 0;
#else
outbytes[i] = 0;
outbytes[i + 1] = x;
outbytes[i + 2] = y;
outbytes[i + 3] = z;
#endif
}
n >>= 2;
break;
case 2:
words = (int16_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (words[i]) << 16;
}
break;
case 1:
sbytes = (int8_t *) buffer;
for (i = 0; i < n; ++i) {
samples[i] = (int32_t) (sbytes[i]) << 24;
}
break;
}
return n;
}
and
int AIFF_CloseFile(AIFF_Ref ref)
{
int r;
if (!ref)
return -1;
if (ref->flags & F_RDONLY) {
AIFF_ReadClose(ref); // BREAK OCCURS HERE EVERYTIME
r = 1;
} else if (ref->flags & F_WRONLY) {
r = AIFF_WriteClose(ref);
} else {
r = -1;
}
return r;
}
The break occurs at AIFF_ReadClose(ref); EVERYTIME. So I have also shown this function below.
static void AIFF_ReadClose(AIFF_Ref r)
{
if (r->buffer)
free(r->buffer);
if (r->buffer2)
free(r->buffer2); // THIS IS WHERE THE BREAK OCCURS EVERYTIME
Unprepare(r);
fclose(r->fd);
free(r);
return;
}
The break always occurs as shown above. The following is the error message: (25693,0x7fff7db87310) malloc: * error for object 0x4000000000000000: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
So basically, the above error occurs unpredictably. When it doesn't occur, my code works perfectly. Any help as to how I might solve this problem is much appreciated.
IF ANYONE IS WILLING TO DOWNLOAD THE LIBAIFF LIBRARY TO INVESTIGATE FURTHER AND HELP ME OUT, the link to the library is: http://aifftools.sourceforge.net/libaiff/.
Thanks in advance for any suggestions!
1, please confirm buffer2 has been initialized with NULL before using. In all your pasted codes, I can not find any assignment or memory allocation for buffer2.
2, please assign the pointer with NULL after calling free, like:
if (r->buffer)
{
free(r->buffer);
r->buffer = NULL;
}
if (r->buffer2)
{
free(r->buffer2);
r->buffer2 = NULL;
}
If all this can not resolve you problem, please give more code about buffer2.