C: never getting to return statement - c

I am implementing a program which hides messages in ppm files and then retrieves them. One of the last things I need to do is to "return 2" if there is a problem opening the file. If I enter a file which can't be opened (file doesn't exist or wrong extension, etc) then it will display the error message on stderr, but for some reason it won't execute the very next line, "return 2"!
It simply then returns 0 instead of returning 2.
int load_ppm_image(const char *input_file_name, unsigned char **data, int *n,
int *width, int *height, int *max_color)
{
char line[80];
char c;
FILE * image_file;
//image_file = fopen(input_file_name, "rb");
if (fopen(input_file_name, "rb") == NULL) // checks to see if file cant be opened
{
fprintf(stderr, "The input image file could not be opened\n");
return 2; // why isn't this being returned???
}
else
{
image_file = fopen(input_file_name, "rb");
}
fscanf(image_file, "%s", line);
fscanf(image_file, "%d %d", width, height);
*n = (3 * (*width) * (*height));
fscanf(image_file, "%d%c", max_color, &c);
*data = (unsigned char *)malloc((*n)*sizeof(unsigned char));
size_t m = fread(*data, sizeof(unsigned char), *n, image_file);
assert(m == *n);
fclose(image_file);
return 0;
}
int hide_message(const char *input_file_name, const char *message, const char *output_file_name)
{
unsigned char * data;
int n;
int width;
int height;
int max_color;
n = 3 * width * height;
int code = load_ppm_image(input_file_name, &data, &n, &width, &height, &max_color);
if (code)
{
// return the appropriate error message if the image doesn't load correctly
return code;
}
int len_message;
int count = 0;
unsigned char letter;
// get the length of the message to be hidden
len_message = (int)strlen(message);
for(int j = 0; j < len_message; j++)
{
letter = message[j];
int mask = 0x80;
// loop through each byte
for(int k = 0; k < 8; k++)
{
if((letter & mask) == 0)
{
//set right most bit to 0
data[count] = 0xfe & data[count];
}
else
{
//set right most bit to 1
data[count] = 0x01 | data[count];
}
// shift the mask
mask = mask>>1 ;
count++;
}
}
// create the null character at the end of the message (00000000)
for(int b = 0; b < 8; b++){
data[count] = 0xfe & data[count];
count++;
}
// write a new image file with the message hidden in it
int code2 = write_ppm_image(output_file_name, data, n, width, height, max_color);
if (code2)
{
// return the appropriate error message if the image doesn't load correctly
return code2;
}
return 0;
}
Edit:
int main(int argc, const char * argv[])
{
if (argc < 2 || argv[1][0] != '-')
{
// the user didn't enter a switch
fprintf(stderr, "Usage: no switch was entered.\n");
return 1;
}
else if ((strcmp(argv[1], "-e") == 0) && (argc == 5))
{
// hides a message in an output file
hide_message(argv[2], argv[3], argv[4]);
}
else if ((strcmp(argv[1], "-d") == 0) && (argc == 3))
{
// retrieves a hidden message in a given file
retrieve_message(argv[2]);
}
else
{
// all other errors prompt a general usage error
fprintf(stderr, "Usage: error");
return 1;
}
}

Program ended with exit code: 0
The exit code of a C program is the return value of main or the status value in an explicit exit function call. In your case, the load_ppm_image returns a value to its caller function hide_message which in turn returns the same value to its caller function main. However, main does not explicitly return anything for the case that calls hide_message. The C standard specifies that main implicitly returns 0 if it reaches the end of the function without an explicit return. Hence the exit code of 0 in your case.
To get the behaviour you desire modify your main code to return the hide_message return value.
else if ((strcmp(argv[1], "-e") == 0) && (argc == 5))
{
// hides a message in an output file
return (hide_message(argv[2], argv[3], argv[4]));
}

From code :
In main function you are calling the hide_message function, but not collecting return value of hide_message()
hide_message(argv[2], argv[3], argv[4]);
So the main function is ending with return 0.

Related

Compare two binary files in C

I am writing a program to compare two binary files and plot the first difference. I want to read 16 bytes of data from each file continuously and compare them. For that I am storing 16 bytes from both file into char *buffer1, buffer2. When I print the output I am getting that buffer1 has both the data of file1 and file2.
The code is as follows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void printConversion(char *buf1, char *buf2) {
size_t len = strlen(buf1);
char *binary = malloc(len * 8 + 1);
binary[0] = '\0';
for (size_t i = 0; i < len; ++i) {
char ch = buf1[i];
for (int j = 7; j >= 0; --j) {
if (ch & (1 << j)) {
strcat(binary,"1");
} else {
strcat(binary,"0");
}
}
}
printf("File1: %s\t", binary);
free(binary);
printf("File2:");
for (int i = 0; i < sizeof(buf2); i++) {
printf("%x", buf2[i] - '0');
}
}
void fileRead(FILE *fp, char *buf, int count) {
fseek(fp, count, SEEK_SET);
fread(buf, 1, 16, fp);
}
int fileSize(FILE *fp) {
fseek(fp, 0, SEEK_END);
int size = ftell(fp) + 1;
return size;
}
int main(int argc, char *argv[]) {
printf("***Binary File Comparator***\n ");
int count = 0;
int index = 0;
char buffer1[16];
char buffer2[16];
char buffer3[16];
char buffer4[16];
// Invalid Number of Arguments
if (argc < 3 || argc > 3) {
printf("Invalid Number of Arguments\n");
}
FILE *fp1, *fp2;
fp1 = fopen(argv[1], "rb");
int size = fileSize(fp1);
int size1 = size;
fclose(fp1);
while (size > 1) {
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer1, count);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer2, count);
if (size1 < count) {
int lastSize = count - size1;
count = count + lastSize;
fclose(fp2);
} else {
count = count+16;
fclose(fp2);
}
**printf("buffer1:%s\tbuffer2:%s\n", buffer1, buffer2)**;
size = size - 16;
int result = strcmp(buffer1, buffer2);
if (result != 0) {
for (int i = 0; i < sizeof(buffer1); i++) {
if (buffer1[i] != buffer2[i]) {
int count1 = (count - 16) + i;
index++;
if (index == 1) {
printf("Byte_Offset:%x\n", count1);
fp1 = fopen(argv[1], "rb");
fileRead(fp1, buffer3, count1);
fclose(fp1);
fp2 = fopen(argv[2], "rb");
fileRead(fp2, buffer4, count1);
fclose(fp2);
printConversion(buffer3, buffer4);
break;
}
} else {
continue;
}
}
}
}
}
I have tried to highlight the printf part that is printing my buffer1 and buffer2
The output is as follows:
buffer1:83867715933586928386771593358692 buffer2:8386771593358692
buffer1:49216227905963264921622790596326 buffer2:4921622790596326
buffer1:40267236116867294026723611686729 buffer2:4026723611686729
buffer1:82306223673529228230622367352922 buffer2:8230622367352922
buffer1:25869679356114222586967935611422 buffer2:2586967935611422
Can anybody help what I am doing wrong. Please point me the error and what optimization changes could be done in code. I am at learning stage your feedback will be very helpful.
You are complicating the task by reading 16 bytes at a time. If the goal is to indicate the first difference, just read one byte at a time from both files with getc() this way:
int compare_files(FILE *fp1, FILE *fp2) {
unsigned long pos;
int c1, c2;
for (pos = 0;; pos++) {
c1 = getc(fp1);
c2 = getc(fp2);
if (c1 != c2 || c1 == EOF)
break;
}
if (c1 == c2) {
printf("files are identical and have %lu bytes\n", pos);
return 0; // files are identical
} else
if (c1 == EOF) {
printf("file1 is included in file2, the first %lu bytes are identical\n", pos);
return 1;
} else
if (c2 == EOF) {
printf("file2 is included in file1, the first %lu bytes are identical\n", pos);
return 2;
} else {
printf("file1 and file2 differ at position %lu: 0x%02X <> 0x%02X\n", pos, c1, c2);
return 3;
}
}
In terms of efficiency, reading one byte at a time does not pose a problem if the streams are buffered. For large files, you can get better performance by memory mapping the file contents if available on the target system and for the given input streams.
Not an actual answer, but a word on optimisation. You can increase the speed of the program if you have a bigger buffer. Basically the larger the buffer the faster the program runs HOWEVER the speed you gain from just making it larger will increase logarithmically.
Here is a picture of a graph that will help you understand. Also, what i mentioned applies to any simmilar situation. This includes: Copying files, filling the sound buffer etc. Loading the entire file in your RAM first and operationg on it will usually be faster than loading parts of it. Ofc this is not possible with larger files but still this is what you should aim for if you want speed.
PS: I'm writting here because i don't have rep to comment.
EDIT: I came up with solution but since you did not state what you need to do with your buffer3 and buffer4 i packed it up inside a function.
If you are sure that you are only going to use 16 bytes as a buffer size, remove the nBufferSize parameter and replace the buffer dynamic allocation with a static one.
If after the execution you need the buffers, add them as parameters and keep the nBufferSize param. Keep in mind that if you intend to use them outside the function, you should also allocate them outside the function, so things don't get messy.
/** Returns 0 if files are identical, 1 if they are different and -1 if there
is an error. */
int FileCmp(char* szFile1, char* szFile2, int nBufferSize)
{
FILE *f1, *f2;
f1 = fopen(szFile1, "rb");
f2 = fopen(szFile2, "rb");
// Some error checking?
if (f1 == NULL || f2 == NULL)
return -1;
// You can check here for file sizes before you start comparing them.
// ...
// Start the comparrison.
/// Replace this part with static allocation. --------
char* lpBuffer1 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer1 == NULL) // close the files and return error.
{
fclose(f1);
fclose(f2);
return -1;
}
char* lpBuffer2 = malloc(sizeof(char)*nBufferSize);
if (lpBuffer2 == NULL) // close the files, free buffer1 and return error.
{
free(lpBuffer1);
fclose(f1);
fclose(f2);
return -1;
}
/// --------------------------------------------------
while(1)
{
unsigned int uRead1 = fread(lpBuffer1, sizeof(char), nBufferSize, f1);
unsigned int uRead2 = fread(lpBuffer2, sizeof(char), nBufferSize, f2);
if (uRead1 != uRead2)
goto lFilesAreDifferent;
for(unsigned int i = 0; i < uRead1; i++)
if (lpBuffer1[i] != lpBuffer2[i])
goto lFilesAreDifferent;
if ((feof(f1) != 0) && (feof(f2) != 0))
break; // both files have nothing more to read and are identical.
goto lSkip;
lFilesAreDifferent:
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 1;
lSkip:;
}
// The files are the same. Close them, free the buffers and return 0.
free(lpBuffer1);
free(lpBuffer2);
fclose(f1);
fclose(f2);
return 0;
}
A simple Demo:
#define BUFFER_SIZE 16
int main(int nArgs, char** szArgs)
{
if (nArgs != 3)
{
printf("Invalid number of arguments.");
return 0;
}
int nResult = FileCmp(szArgs[1], szArgs[2], BUFFER_SIZE);
switch (nResult)
{
case 0: printf("Files [%s] and [%s] are identical.", szArgs[1], szArgs[2]); break;
case 1: printf("Files [%s] and [%s] are different.", szArgs[1], szArgs[2]); break;
case -1: printf("Error."); break;
}
return 0;
}
EDIT II: Personally, i have never used the C standard FILE library (it was either C++ fstream or pure win32 fileapi) so don't take my word here for granted but fread is the fastest function i could find (faster than fgets or fgetc). If you want even faster than this you should get into OS dependant functions (like ReadFile() for Windows).
chqrlie's solution using getc is absolutely the right way to do this. I wanted to address some points brought up in comments, and find it's best to do that with code. In one comment, I recommend pseudo code which could be confusing (namely, you can't write fwrite(file1...) || fwrite(file2 ...) because of the short circuit. But you can implement the idea of that with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
* Compare two files, 16 bytes at a time. (Purely to demonstrate memcmp.
* Clearly, this should be implemented with getc.)
*/
FILE * xfopen(const char *, const char *);
size_t xfread(void *, FILE *, const char *);
int
main(int argc, char **argv)
{
FILE *fp[2];
size_t n[2];
char buf[2][16];
unsigned count = 0;
if(argc != 3) { return EXIT_FAILURE; }
fp[0] = xfopen(argv[1], "r");
fp[1] = xfopen(argv[2], "r");
do {
n[0] = xfread(buf[0], fp[0], argv[1]);
n[1] = xfread(buf[1], fp[1], argv[2]);
if( n[0] != n[1] || (n[0] && memcmp(buf[0], buf[1], n[0]))) {
fprintf(stderr, "files differ in block %u\n", count);
return 1;
}
count += 1;
} while(n[0]);
puts("files are identical");
return 0;
}
size_t
xfread(void *b, FILE *fp, const char *name)
{
size_t n = fread(b, 1, 16, fp);
if(n == 0 && ferror(fp)) {
fprintf(stderr, "Error reading %s\n", name);
exit(EXIT_FAILURE);
}
return n;
}
FILE *
xfopen(const char *path, const char *mode)
{
FILE *fp = strcmp(path, "-") ? fopen(path, mode) : stdin;
if( fp == NULL ) {
perror(path);
exit(EXIT_FAILURE);
}
return fp;
}

Problem with Chatbot,how to count occurrences of some words in a text file in C

I'm building a polling command for my Twitch Chatbot, but i'm having problems
in handling the votes. I need to count the occurrences of a vote in a text file.
For now, i did this, but it doesn't seem to work properly:
struct VoteData GetMostVote(FILE * fp)
{
char * buffer = (char *)malloc(sizeof(char)*MAX_BUFFER);
int lines = GetLines(fp);
struct VoteData data[lines];
int i = 0;
while(fgets(buffer, MAX_BUFFER, fp) != NULL)
{
if(strcmp(data[i].word, buffer) == 0)
{
data[i].freq += 1;
}
else
{
strcpy(data[i].word, buffer);
}
i++;
}
int c = 0, index = 0;
for(int j = 0; j < sizeof(data)/sizeof(struct VoteData); j++)
{
if(data[j].freq > c)
{
index = j;
c = data[j].freq;
}
}
free(buffer);
return data[index];
}
where the structure VoteData has this form:
struct VoteData
{
char word[128];
int freq;
};
The function GetMostVote() should return a structure VoteData containing the word with more occurrences in the text file and the frequency for that word.
But my chatbot replies with a string which i'm using in another function...and that is strange.
EDIT1:
I suppose is necessary to also post the function where GetMostVote() gets called:
void poll_handler(int sock, int * status, int * vote_count)
{
FILE * fp;
int res;
char * string = (char *)malloc(sizeof(char)*MAX_BUFFER);
struct VoteData vote;
sleep(300);
*status = 0;
*vote_count = 0;
if(!(fp = fopen("polls/votes.txt", "r")))
{
fprintf(stderr, "\nError in reading file\n");
exit(EXIT_FAILURE);
}
vote = GetMostVote(fp);
strcpy(string, "PRIVMSG #st3ver0nix : Polling terminated, the majority voted: ");
strcat(string, vote.word);
strcat(string, "\r\n");
do{
res = write(sock, string, strlen(string));
}while(res < strlen(string));
fclose(fp);
free(string);
}
the parameters are: the socket of the irc channel, the status and the vote_count pointers to int which are used for handling the votes.
EDIT2:
I'm posting also the function where poll_handler() gets called:
void CreatePoll(int sock, char * message, char * poll_name, int * status, int * vote_count)
{
pid_t pid;
char * name = (char *)malloc(sizeof(char)*MAX_BUFFER);
GetPollName(message, name);
strcpy(poll_name, name);
if((pid = fork()) == -1)
{
fprintf(stderr, "\nError in fork\n");
exit(EXIT_FAILURE);
}
if(pid == 0)
{
poll_handler(sock, status, vote_count);
}
free(name);
}
return data[index] attempts to return a local variable.
That is no problem at all, since the value of data[index] is returned, not its address.
The main error in GetMostVote() is that in the while loop the vote line just read is compared to the uninitialized data[i].word. Correct is to compare the current vote to the previously stored vote data until there are no more or the current vote is found among them:
while (fgets(buffer, MAX_BUFFER, fp) != NULL)
for (int j = 0; ; ++j)
if (j == i)
{ // store new word
data[i].freq = 1;
strcpy(data[i++].word, buffer);
break;
}
else
if (strcmp(data[j].word, buffer) == 0)
{ // count known word
data[j].freq += 1;
break;
}
A second error is in the for(int j = 0; j < sizeof(data)/sizeof(struct VoteData); j++): Rather than going through all allocated vote data, of which the posterior may well be uninitialized, only the used data shall be regarded:
for (int j = 0; j < i; j++)

open file in C and I don't know how do I get the width and height of the file

This is my code to open any file from the console.
But, I don't know how I get the width and height of the file automatically.
#include <stdio.h>
int main(int argc, char *argv[]){
char dat;
FILE *fs;
fs = fopen(argv[1], "r");
while((dat = fgetc(fs))!=EOF){
printf("%c",dat);
}
fclose(fs);
printf("\n");
return 0;
}
With width and high you mean the number of rows and columns of the file?
In this case you can check the newline character:
int rows = 0;
int cols = 0;
int rowcols = 0;
while ((dat = fgetc(fs)) != EOF) {
if (dat == '\n') {
if (rowcols > cols) {
cols = rowcols;
}
rowcols = 0;
rows++;
} else {
if (dat != '\r') { /* Do not count the carriage return */
rowcols++;
}
}
printf("%c",dat);
}
/* If the file does not end with a newline */
if (rowcols != 0) {
if (rowcols > cols) {
cols = rowcols;
}
rows++;
}
printf("Rows = %d, Cols = %d\n", rows, cols);
On the other hand, always check the number of arguments passed to main and the result of fopen:
if (argc < 2) {
fprintf(stderr, "Usage = %s file\n", argv[0]);
exit(EXIT_FAILURE);
}
...
fs = fopen(argv[1], "r");
if (fs == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
Here is the sample code. explanation I wrote in comments
int main(int argc, char *argv[]){
FILE *fs;
fs = fopen(argv[1], "r");
/* always check return value of fopen() */
if(fs == NULL) {
/* put some mesage */
return 0;
}
/* width width means which lines having max no of characters */
/* step-1 : use fgets() bcz it read line by line */
char buf[100];/* assuming each line have less than 100 char */
int width = 0,len = 0,height = 0;
while(fgets(buf,sizeof(buf),fs)) {
/* now buf having one line, your job is find the length of each line
and do comparison mechanism */
len = strlen(buf);
if(width < len) {
width = len;
}
height++;/* its height bcz when above loop fails
height value is nothing but no of line in file*/
}
printf("width = %d and height = %d \n",width,height );
fclose(fs);
return 0;
}
To know how fgets() works. open man 3 fgets from command line & check.

Calling my function, causes the program to crash - C | 3DS Homebrew

I've been writing a homebrew for the Nintendo 3DS, which is written in C. It simply parses a JSON file and prints it onto the screen. The problem is that after parsing and printing it on the screen, it just crashes.
Code:
char JSON_FILE[] = "jsbr-ford-mustang.json";
static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
return 0;
}
return -1;
}
const char * parse_json(char* value) {
u8* file_buffer; FILE *file = fopen(JSON_FILE,"rb"); if (file == NULL) printf("Error.\n");
fseek(file,0,SEEK_END); off_t size = ftell(file); fseek(file,0,SEEK_SET); file_buffer=malloc(size);
if(!file_buffer) printf("Error.\n");
off_t bytesRead = fread(file_buffer,1,size,file); fclose(file);
if(size!=bytesRead) printf("Error.\n");
int i; int r;
jsmn_parser p; jsmntok_t t[128]; jsmn_init(&p);
r = jsmn_parse(&p, file_buffer, size, t, sizeof(t)/sizeof(t[0]));
if (r < 0) {
printf("Failed to parse JSON: %d\n", r);
return 1;
}
if (r < 1 || t[0].type != JSMN_OBJECT) {
printf("Object expected\n");
return 1;
}
printf("Debug START\n");
for (i = 1; i < r; i++) {
if (jsoneq(file_buffer, &t[i], value) == 0) {
printf("Debug 1\n");
break;
}
printf("Debug 2\n");
}
printf("Debug 3\n");
return printf("%.*s\n", t[i+1].end-t[i+1].start, file_buffer + t[i+1].start);
}
int main() {
gfxInitDefault();
consoleInit(GFX_TOP,NULL);
printf("P1\n");
printf("Description: %s",parse_json("description"));
printf("P2\n");
printf("Sync spacing: %s",parse_json("synchronization_spacing_us"));
while (aptMainLoop()) {
hidScanInput(); u32 kDown = hidKeysDown();
if(kDown & KEY_START) {
consoleClear();
break;
}
gfxFlushBuffers();
gfxSwapBuffers();
}
gfxExit();
return 0;
}
Debug output:
P1
Debug START
Debug 2
Debug 2
Debug 1
Debug 3
Ford Mustang, 40MHz, No. 23019
Here is a video of what happens: https://www.youtube.com/watch?v=zpt_BEMyIOc
Here is the GitHub repo that I have for it: https://github.com/lavanoid/3DS_JSON_Parser
from cplusplus.com regarding the return value of printf():
On success, the total number of characters written is returned.
If a writing error occurs, the error indicator (ferror) is set and a negative number is returned.
If a multibyte character encoding error occurs while writing wide characters, errno is set to EILSEQ and a negative number is returned.
you cannot do this: return printf("%.*s\n", t[i+1].end-t[i+1].start, file_buffer + t[i+1].start);
because your function needs to return a const char *, not an int, which is returned from printf().
You should use sprintf() to print the string you want into a buffer (tempString for example)
static char *tempString;
...
if(tempstring != NULL) {
free(tempString);
tempString = NULL;
}
tempString = (char *)malloc(t[i+1].end-t[i+1].start+1);
if(tempString != NULL) {
sprintf(tempString,"%s", file_buffer + t[i+1].start);
return (const char *)tempString;
} else {
return "malloc error!";
}

int value changed unexpected

I meet a problem of a c program: the int variable is changed unexpected.
Below is all about the problem:
I try to read a txt file which looks like:
2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success
It is a log file which will record the start/finish time of a task. I want to parse the log file and find the finished task record in a order time(latest first). For example, I will try to read the last line and it shows that the task is running. Hence I ignore it and continue to read the last 2nd line. In general the next two line which has "ended" and "started" in pairs can be marked as a record.
My environment is: Centos6.5 (installed via VMWaire).
Below is the source code and it uses libccgi:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "json/json.h"
#include "ccgi.h"
#include <errno.h>
const char *queryName = "account";
const char *queryPage = "pageIndex";
const char *startAction = "/activeJob/start/";
const char *finishAction = "/activeJob/finish/";
const char *contentDes[] = {"there is backup processing, start at :","there is no backup"};
const float pageNums = 8.0;
const char * jsonStringCreate(json_object *jsonObj,int statueCode, char *content, int totalPages)
{
json_object_object_add(jsonObj, "statueCode", json_object_new_int(statueCode));
json_object_object_add(jsonObj, "content", json_object_new_string(content));
json_object_object_add(jsonObj, "totalPages", json_object_new_int((int)totalPages));
//the memory of returned string is under control of jsonObj
return json_object_get_string(jsonObj);
}
char *mallocString(char *string)
{
char *returnString = malloc(sizeof(char) * (1 + strlen(string)));
strcpy(returnString, string);
//owner free the returned string
return returnString;
}
/* File must be open with 'b' in the mode parameter to fopen() */
/* Set file position to size of file before reading last line of file */
char* fgetsr(char* buf, int n, FILE* binaryStream)
{
long fpos;
int cpos;
int first = 1;
if (n < 1 || (fpos = ftell(binaryStream)) == -1 || fpos == 0)
return NULL;
cpos = n - 1;
buf[cpos] = '\0';
for (;;)
{
int c;
if (fseek(binaryStream, --fpos, SEEK_SET) != 0 ||
(c = fgetc(binaryStream)) == EOF)
return NULL;
if (c == '\n' && first == 0) /* accept at most one '\n' */
break;
first = 0;
if (c != '\r') /* ignore DOS/Windows '\r' */
{
unsigned char ch = c;
if (cpos == 0)
{
memmove(buf + 1, buf, n - 2);
++cpos;
}
memcpy(buf + --cpos, &ch, 1);
}
if (fpos == 0)
{
fseek(binaryStream, 0, SEEK_SET);
break;
}
}
memmove(buf, buf + cpos, n - cpos);
return buf;
}
</code></pre>
<pre><code>
int main(int argc, char const *argv[], char **env)
{
int statueCode = 0;
int totalPages = 0;
char *content = NULL;
json_object *jsonObj = json_object_new_object();
printf("Content-type: text/plain; encoding=utf-8\n\n");
CGI_varlist *vl;
const char *name;
CGI_value *value;
int i;
if ((vl = CGI_get_all("/tmp/cgi-upload-XXXXXX") ) == 0)
{
// CGI error
// fputs("CGI_get_all() failed\r\n", stdout);
statueCode = 501;
content = mallocString("CGI error");
}
else
{
//get the CGI env parameters, next to get the query parameter
char *accountName = NULL;
int queryIndex = -1;
for (name = CGI_first_name(vl); name != 0; name = CGI_next_name(vl))
{
value = CGI_lookup_all(vl, 0);
for ( i = 0; value[i] != 0; ++i)
{
if (strcmp(name, queryName) == 0)
{
accountName = malloc(sizeof(char) * (strlen(value[i]) + 4 + 1));
strcpy(accountName, value[i]);
strcat(accountName, ".log");
}
else if (strcmp(name, queryPage) == 0)
{
queryIndex = atoi(value[i]);
}
}
}
if (accountName == NULL || queryIndex < 0)
{
statueCode = 502;
content = mallocString("wrong query parameters format");
}
else
{
//for test, need remove
FILE *logFile = fopen("./test#mail.com.log", "rb");
// FILE *logFile = fopen(accountName, "r");
char *lastLineStr = NULL;
int lineNum = 0;
if (logFile != NULL)
{
//log file is found
char *line = NULL;
size_t len = 0;
ssize_t read;
while( (read = getline(&line, &len, logFile)) != -1)
{
// printf("%s\n", line);
if (strstr(line, finishAction) != 0)
{
/* code */
totalPages ++;
}
lineNum ++;
}
free(line);
int realPage = ceil(totalPages/pageNums);
if (queryIndex > realPage)
{
/* code */
statueCode = 503;
content = mallocString("wrong parameter: query index is beyond the total page");
}
else
{
//log file exist and query index is valid
long startIndex = 0, endIndex = 0, currentIndex = 0;;
startIndex = (queryIndex - 1) * pageNums;
endIndex = (queryIndex) *pageNums;
currentIndex = startIndex;
char buf[256];
int isFinishFound = -1;
int isStartFound = -1;
char *finishContetn[] = {};
char *startContent[] = {};
// this is the core part
while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex lt; endIndex)
{
if (strstr(buf, finishAction) != 0)
{
/* code */
if (isFinishFound > 0)
{
/* code */
continue;
}
else
{
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
}
}// strange part:
else if (strstr(buf, startAction) != 0)
{
//finish is not found, means: a start with no finish pairs
if (isFinishFound < 0)
{
/* code */
continue;
}
else
{
if (isStartFound < 0)
{
/* code */
startContent[currentIndex] = mallocString(buf);
isStartFound = 1;
isFinishFound = -1;
currentIndex ++;
}
else
{
continue;
}
}
}
}
}
}
else
{
//log file is not found
statueCode = 400;
content = mallocString("not found the account log");
// printf("not found\n");
// fprintf(stderr, "%d: %s\n", errno, strerror(errno) );
}
if (logFile)
{
fclose(logFile);
}
}
}
return 0;
}
The libjson and libccgi is placed in the right place and I build and make it like:
/usr/local/bin/clang -I /usr/include -DHAVE_SSL -DCLDMAN -DCLDMAN_USE_RETRY -DUSE_PROXY -c -MMD -fPIC -g -DHAVE_SSL -DCLDMAN -I../../build/include -I../../build/include/curl -I../../build/include/json -I../../build/include/svmdisk -o getLog.o getLog.c
/usr/local/bin/clang -o getLog getLog.o -L../../build/lib -lm -lccgi -ljson
and it has no error in the terminal.
The problem I met is the value of int isStartFound will has a strange value of 134538336. It happen when I debug as following:
in the while, the currentIndex=1 which means it begins to find the second record
it finds the "finish", and it begins to do:
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
After that, it runs to the while again, and now the isStartFound is changed to 134538336.
I also try to add isStartFound to the watch variable. And it also shows in the "strange part"(which I add in the code) the value of isStartFound changes from -1 to 134538336.
I can't find where this value comes from. I doubt that the way I build and link is wrong. But I failed to find it.
Could any one suggest the way how can I look into?
Thanks!
=======edited:
The problem mainly locates the code below:
char buf[256];
int isFinishFound = -1;
int isStartFound = -1;
while(fgetsr(buf, sizeof(buf), logFile) != NULL && currentIndex 0)
{
continue;
}
else
{
isFinishFound = 1;
isStartFound = -1;
finishContetn[currentIndex] = mallocString(buf);
}
}// here strange happens: the isStartFound changes!
else
{
// other part
}
}
fgetsr is used to read one line of the text; isStartFound&isFinishFound are 2 mask to show whether the "start"/"finish" record is found.
The problem comes with a precondition:the first record is found and now we are try to read the last 5th line(which is the 2nd line). The text file is :
2013/12/31 19:53:54, started, /activeJob/start/ Failed
2013/12/31 19:55:55, ended, retCode = 6, Couldn't resolve host name, /activeJob/finish/ Failed
2014/01/01 08:06:55, started, /activeJob/start/ Failed
2014/03/04 12:16:55, started, /activeJob/start/ Success
2014/03/04 12:17:25, ended, retCode = 0, No error, /activeJob/finish/ success
2014/03/04 13:57:21, started, /activeJob/start/ Success
Now it begins to read the 2nd line and finds "finish", and hence it need to mark the var: isStartFound = -1.
When the program runs to the first "}", the isStartFound is -1. But when it runs to the second "}"(which is the "}" of if (strstr(buf, finishAction) != 0)), the value changes: siStartFound = 134538336!( I add comment in the code) As you can see, here nothing is done!
This is my question and where I feel it weird. (Sorry for the too long code. If this edition still troubles you, please tell me.)
The problem is this declaration:
char *finishContetn[] = {};
This declares finishContetn as an empty array of pointers. Being empty, no matter what index you use to access this array, it will be out of bounds.
As you assign to this array:
finishContetn[currentIndex] = mallocString(buf);
you will write beyond the bounds, and will have undefined behavior. In this case, you will overwrite the stack where other variables are located, like for example the isStartFound variable.
A way to solve this is to either set a fixed size, or to use a dynamic "array". The dynamic array solution requires you to declare the variable as a pointer to pointer (to char) and use realloc to (re)allocate the array.
Something like
char **finishContent = NULL;
size_t finishContentSize = 0; /* Current size of the array */
...
char **temp = realloc(finishContent, sizeof(finishContent[0]) * finishContentSize + 1);
if (temp != NULL)
{
finishContent = temp;
finishContent[finishContentSize++] = malloc(...);
}
Note that I use a temporary variable for the return of realloc, this is because if realloc fails then it won't free finishContent for you, and if you assign directly to finishContent you will loose your original pointer and can't free it later.
Also note that I use sizeof(finishContent[0]). This will work even when finishContent is NULL because sizeof is a pure compile-time operator, it will not create any run-time code.
You might of course need to modify the code to fit your application, but the above should be enough to give you an idea.

Resources