I was writing a C program that reads the width and heights of a bmp image following (http://smsoftdev-solutions.blogspot.com.au/2014/07/code-for-reading-bmp-image-files.html). But I've met an error in terminal, it shows that:
i './a.out' terminated by signal SIGSEGV (Address boundary error)
I did some googling, they mention it's accessing extra memory problem, but I can't really find that in my code, any suggestion would be appreciated
#include <stdio.h>
struct __attribute__((__packed__)) BitmapHeader
{
int width;
int height;
};
void loadBmp(char* filePath, struct BitmapHeader bmpHeaderInfo){
FILE* filePtr = fopen(filePath, "rb");
unsigned char header[54];
fread(header, sizeof(unsigned char), 54, filePtr);
}
int main(){
char path2BMP[] = "/cup.bmp";
struct BitmapHeader bmpHeaderInfo = {0};
loadBmp(path2BMP, bmpHeaderInfo);
return 0;
}
Related
This is in a program meant to work with ppm image files.
I'm getting a compilation error when trying to modify a struct and then writing it to a new file.
This is the global struct (declared in ppmIO.c and ppmIO.h):
ppmIO.c:
struct Image *instance;
ppmIO.h:
struct Image
{
int width;
int height;
unsigned char *data;
};
extern struct Image *instance;
This is my imageManip.h file:
#include <ppmIO.h>
void ImageInvert(struct Image **toInvert);
void ImageSwap(struct Image **toSwap);
These are the relevant parts of my imageManip.c file:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <ppmIO.h>
#include <imageManip.h>
void ImageInvert(struct Image **toInvert) {
int i;
int pix = (*toInvert->width) * (*toInvert->height);
*toInvert = realloc(*toInvert, 2* sizeof *instance);
for (i = 0; i < pix; i++)
{
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data));
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data++));
*(toInvert)->data = ((unsigned char)255 - *(toInvert)->data++));
}
}
void ImageSwap(struct Image **toSwap) {
int i;
int pix = (*toSwap)->width * (*toSwap)->height;
*toSwap = realloc(*toSwap, 2* sizeof *instance);
unsigned char what = (*toSwap)->data;
for (i = 0; i < pix-1; i++)
{
(*toSwap)->data = (*toSwap)->data++;
(*toSwap)->data = (*toSwap)->data++;
(*toSwap)->data = what;
what = (*toSwap)->data++;
}
}
This is the ImageWrite method, used to write the modified image structure to a file:
void ImageWrite(char *filename)
{
int num;
printf("%d", num);
int size = (instance->width) * (instance->height) * 3;
FILE *fp = fopen(filename, "w");
if (!fp) die("cannot open file for writing\n");
fprintf(fp, "P6\n%d %d\n%d\n", instance->width, instance->height, 255);
num = fwrite((void *) instance->data, 1, (size_t) size, fp);
if (num != size) die("cannot write image data to file\n");
fclose(fp);
}
This is how I call my modifying functions from main:
ImageInvert(&instance);
ImageSwap(&instance);
ImageWrite(first); //where first is a filename
This is the segmentation fault that gdb reports:
Program received signal SIGSEGV, Segmentation fault.
__mempcpy_sse2 () at ../sysdeps/x86_64/memcpy.S:166
166 ../sysdeps/x86_64/memcpy.S: No such file or directory.
Someone suggested that in my modifying funtions (ImageInvert and ImageSwap), I keep changing the pointer, not the data pointed at. If that is the case, how can I change the data pointed at instead of just the pointer?
As noted in comments to a previous question, the code for ImageInvert() can be made much simpler.
Using subscript notation:
void ImageInvert(struct Image **toInvert)
{
struct Image *image = *toInvert;
int n_colour_vals = (image->width * image->height) * 3;
unsigned char *data = image->data;
for (int i = 0; i < n_colour_vals; i++)
data[i] = 255 - data[i];
}
Using pointers:
void ImageInvert(struct Image **toInvert)
{
struct Image *image = *toInvert;
unsigned char *data = image->data;
unsigned char *end = data + (image->width * image->height) * 3;
while (data < end)
{
*data = 255 - *data;
data++;
}
}
Equivalent changes can probably be made to imageSwap(), though I am not entirely sure what it is supposed to be doing. There were problems in the previous question that might have suggested that the reallocation was a good idea, but (at least for ImageInvert()), that really isn't needed.
This is in a program meant to work with ppm image files.
I'm getting a segmentation fault when trying to read an image from a file and assigning that image to my global struct image.
These are the relevant parts of my ppmIO.c file:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <ppmIO.h>
struct Image *instance;
void ImageRead(char *filename)
{
printf("hi 0!");
int width, height, num, size;
//unsigned char *p;
//Image *image = (Image *) malloc(sizeof(Image));
FILE *fp = fopen(filename, "r");
//if (!image) die("cannot allocate memory for new image");
if (!fp) die("cannot open file for reading");
readPPMHeader(fp, &width, &height);
size = width * height * 3;
printf("hi!");
//instance->data = (unsigned char *) malloc(size);
printf("hi 2!");
instance->width = width;
printf("hi 3!");
instance->height = height;
printf("hi 4!");
if (!instance->data) die("cannot allocate memory for new image");
num = fread((void *) instance->data, 1, (size_t) size, fp);
if (num != size) die("cannot read image data from file");
fclose(fp);
}
This is my ppmIO.h file:
#ifndef PPMIO_H
#define PPMIO_H
struct Image
{
int width;
int height;
unsigned char *data;
};
extern struct Image *instance;
//extern Image *ImageCreate(int width, int height);
//extern void ImageClear(struct Image *image, unsigned char red, unsigned char green, unsigned char blue);
extern void ImageRead(char *filename);
extern void ImageWrite(char *filename);
extern void ImageSetPixel(int x, int y, int chan, unsigned char val);
extern unsigned char ImageGetPixel(int x, int y, int chan);
#endif /* PPMIO_H */
And this is the segmentation fault that GDB reports:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400fff in ImageRead (filename=0x7fffffffdc32 "nika.ppm")
at ppmIO.c:126
126 instance->width = width;
I think there is a problem with how I'm trying to use the Image *instance... but I really have no real clue what is causing this mess. :(
You're getting this error as you have not allocated any memory for instance. Before you try and use any member of instance (i.e. width or data) you must allocate memory (from inside a function), i.e:
instance = malloc(sizeof *instance);
You should not cast the return value of instance (See: this), and there is no need to specify the type since the compiler already knows. You can't allocate the memory when you declare the variable as static initializations must be to constant values (See: this) (the return value of a function is not constant).
You will also need to allocate memory for the instance->data part of the structure, based on the size you read from the file.
I am attempting to write a program to invert the color of an image. My problem is when I try to read from the DIB header in my BMP file.
When I try to get the file header size and use fread(dib.fileheader, 4,1,fp); . I get an error that says "The memory could not be written". I have attached it for further clarification.
Here is my code:
#include <stdio.h>
#include <string.h>
struct BMP {
char filetype[2]; // must be BM, must check if BM
unsigned int filesize;
short reserved1;
short reserved2;
unsigned int dataoffset;
};
struct DIB {
unsigned int fileheader;
unsigned int headersize;
int width;
int height;
short planes;
short bitsperpixel; /* we only support the value 24 here */
unsigned int compression; /* we do not support compression */
unsigned int bitmapsize;
int horizontalres;
int verticalres;
unsigned int numcolors;
unsigned int importantcolors
};
struct pixel {
int val;
char * def;
struct listitem * next;
};
void invertImage(char fileName[]){
struct BMP bmp;
struct DIB dib;
FILE *fp = fopen(fileName, "rb");
//FileType
fread(bmp.filetype, 1,2,fp);
printf("Value is %c\n", bmp.filetype[1]);
//Check if file format is BM
if(bmp.filetype[0] != 'B' && bmp.filetype[1] !='M'){
printf("Wrong format");
}
//Size of the file in bytes
fread(bmp.filesize, 4,1,fp);
printf("Value is %d\n", bmp.filesize);
//Go to dataoffset
fseek(fp,10,SEEK_CUR);
fread(bmp.dataoffset, 4,1,fp);
printf("Offset is %d\n", bmp.dataoffset);
fread(dib.fileheader, 4,1,fp);
printf("File header is %d bytes\n", dib.fileheader);
fclose(fp);
}
int main(int argc, char *argv[] ){
printf("Program name %s\n", argv[0]);
if( strcmp(argv[1],"-invert") == 0) {
printf("Invert\n");
printf("File name is %s\n", argv[2] );
invertImage(argv[2]);
}
else {
printf("Greyscale\n");
//greyScaleImage();
}
return 0;
}
Also here is the output to my program.
fread expects a pointer to memory to write the file contents. So you need to give it the address of dib.fileheader
fread( &dib.fileheader, sizeof(dib.fileheader),1,fp );
printf("File header is %d bytes\n", dib.fileheader);
It's complaining because it's interpreting whatever is in dib.fileheader as the address to write to, which may or may not be valid for your program.
Note that the following is ok as it stands because bmp.filetype is already a pointer to char - it's a char[]
fread(bmp.filetype, 1,2,fp);
printf("Value is %c\n", bmp.filetype[1]);
To make it a bit more general, you could write
fread(bmp.filetype, sizeof(bmp.filetype), 1, fp);
printf("Value is %c\n", bmp.filetype[1]);
I tried to compile your code. You must make some change in your code.
fread(bmp.filesize, 4,1,fp); --- > fread(&bmp.filesize, 4,1,fp);
fread(bmp.dataoffset, 4,1,fp); --- > fread(&bmp.dataoffset, 4,1,fp);
fread(dib.fileheader, 4,1,fp); --- > fread(&dib.fileheader, 4,1,fp);
declare the function : void invertImage(char fileName[]);
I am trying to read 1 block of first hard drive into the memory. I tried with different LBAs but it loads spaces in to the buffer. In following code, i added for loop so that i can see if it loads anything else than just spaces. Do you guys know why it's only loading spaces into the buffer?
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dos.h>
#include <bios.h>
struct DAP
{
unsigned char size;
unsigned char reserved1;
unsigned char blocks;
unsigned char reserved2;
unsigned char far *buffer;
unsigned long int lbalod;
unsigned long int lbahid;
} dap;
char st[80];
unsigned char buf[512];
FILE *fptr;
unsigned long int itrations = 16450559; //10gb
unsigned long int i = 0;
void main(void)
{
clrscr();
for(; i<itrations; i++)
{
dap.size = sizeof(dap);
dap.reserved1 = 0;
dap.blocks = 1;
dap.reserved2 = 0;
dap.buffer = (unsigned char far *)MK_FP(_DS, buf);
dap.lbalod = i;
dap.lbahid = 0;
_AH = 0x42;
_DL = 0x80;
_SI = (unsigned int)&dap;
geninterrupt(0x13);
printf("%lu: %s\n", i, buf);
}
}
It's using Borland Turbo C over VMWare virtual machine that is setup with WinXP. I have also tried the same on DOSBOX on Windows 7. Any help would be much appreciated.
These are only my suggestions in the hope that they help your debugging.
Print sizeof(dap) to ensure that it is indeed 16
Insert memset(buf, 'A', sizeof(buf)); before you issue INT 13h so that you can check buf is modified or not
Try printf("%lu: [%s]\n", i, buf); instead, because when buf contains \0 around its head printf stops there. The braces should work as marks.
Print _AH and _CF which should contain return codes of INT 13h
#include <dos.h>
#include <bios.h>
struct DAP
{
unsigned char size;
unsigned char reserved1;
unsigned char blocks;
unsigned char reserved2;
unsigned char far *buffer;
unsigned long int lbalod;
unsigned long int lbahid;
} dap;
char st[50];
unsigned char buff[256];
FILE *fptr;
main(void)
{
puts ("enter the lba low double word: ");
gets (st);
dap.lbalod=atol(st);
puts ("enter the lba high double word: ");
gets (st);
dap.lbahid=atol(st);
dap.size=16;
dap.reserved1=0;
dap.blocks1;
dap.reserved2=0
dap.buffer = (unsigned char far *)MK FP(DS.buf);
_AH = 0x42;
_DL = 0x80;
_SI = (unsigned int)%dap;
geninterrupt(0x13);
puts ("enter the path: ");
gets(st);
fptr = fopen(st, "wb");
fwrite(buf,256,1,fptr);
fclose(fptr);
}
i am getting statement missing error on this line dap.buffer = (unsigned char far *)MK_FP(_DS, buf);
This is got me pretty stuck, how do I fix this? I know I haven't got error checking, but they aren't required i'd guess since it's restricted to my desktop. It obveously can't be EOF. It's for the infoheader struct, fileheader works fine. Do i need to take a new line or something?
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize;
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
}FILEHEADER;
typedef struct
{
unsigned int biSize;
int width; /* Width of the image */
int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage;
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
}INFOHEADER;
typedef struct
{
unsigned char b; /* Blue value */
unsigned char g; /* Green value */
unsigned char r; /* Red value */
}IMAGECOMPONENT;
int fileheadfunc(FILE *image);
int infoheadfunc(FILE *image);
int main( int argc, char *argv[] )
{
char *filename; /* *threshholdInput = argv[2]; */
FILE *image;
int filehead, infohead;
filename = argv[1];
/* int threshhold = atoi(threshholdInput); */
if (argc != 2)
{
printf(" Incorrect Number Of Command Line Arguments\n");
return(0);
}
image = fopen( filename, "r");
if (image == NULL)
{
fprintf(stderr, "Error, cannot find file %s\n", filename);
exit(1);
}
filehead = fileheadfunc(image);
infohead = infoheadfunc(image);
fclose(image);
return(0);
}
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek (image , 0 , SEEK_SET);
fread( (unsigned char*)header, sizeof(FILEHEADER), 1, image );
if ( (*header).fileMarker1 != 'B' || (*header).fileMarker2 != 'M' )
{
fprintf(stderr, "Incorrect file format");
exit(1);
}
printf("This is a bitmap!\n");
pos = ftell(image);
printf("%ld\n", pos);
printf("%zu\n", sizeof(FILEHEADER));
return(0);
}
int infoheadfunc(FILE *image)
{
INFOHEADER *iheader;
fseek (image, 0, SEEK_CUR );
fread( (unsigned int*)iheader, sizeof(INFOHEADER), 1, image );
printf("Width: %i\n", (*iheader).width);
printf("Height: %i\n", (*iheader).height);
return(0);
}
You're not actually allocating any storage for the BMP header data structures, e.g. you need to change this:
int fileheadfunc(FILE *image)
{
FILEHEADER *header;
long pos;
fseek(image, 0, SEEK_SET);
fread((unsigned char*)header, sizeof(FILEHEADER), 1, image);
...
to this:
int fileheadfunc(FILE *image)
{
FILEHEADER header; // <<<
long pos;
fseek(image, 0, SEEK_SET);
fread(&header, sizeof(FILEHEADER), 1, image); // <<<
...
Also, as previously noted in one of the comments above, you need #pragma pack(1) (or equivalent if you're not using gcc or a gcc-compatible compiler) prior to your struct definitions to eliminate unwanted padding. (NB: use #pragma pack() after your struct definitions to restore normal struct padding/alignment.)
There are two problems with the code:
Alignment
For performance reasons the compiler will, unless instructed to do otherwise, arrange struct fields on its "natural boundaries", effectively leaving uninitialised gaps between byte-size fields. Add
#pragma pack(1)
before the struct definitions and you should be fine. It's also easy to test: just print out the struct size without and with pragma pack in place, and you'll see the difference.
Allocation
As Paul R already said, you should allocate space for the headers, not just provide a pointer to the structures. The fact that fileheadfunc works is a coincidence, there just wasn't anything in the way that got smashed when data got written outside of the allocated space.
A last one, just for prevention sake: should you ever want to return the read structures to the calling program, do not just return a pointer to the structure allocated in the function as that will cause problems similat to the unallocated variables you have now. Allocate them in the calling function, and pass a pointer to that variable to the header read functions.
EDIT clarification regarding the last point:
DON'T
FILEHEADER * fileheadfunc(FILE *image)
{
FILEHEADER header;
...
return &header; // returns an address on the function stack that will
// disappear once you return
}
DO
int fileheadfunc(FILE *image, FILEHEADER *header)
{
...
}
which will be called like this
...
FILEHEADER header;
returnvalue = fileheaderfunc(imagefile,&header);
EDIT2: just noticed that the way you read the DIB header is not correct. There are several variations of that header, with different sizes. So after reading the file header you first need to read 4 bytes into an unsigned int and based on the value read select the correct DIB header structure to use (don't forget you already read its first field!) or tell the user you encountered an unsupported file format.