I have the code below that fixes the IP addresses to 15 digit by padding 0 as prefix.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *function(char *newhost){
char *IPaddr;
IPaddr = (char *)calloc(16, sizeof(char));
size_t i=0 , j= 0;
for(i=0, j=0; j<15; i++, j++){
if((newhost[strlen(newhost)-(i+1)] == '.')){ //////////line 11
if( j == 3 || j == 7 || j == 11){
IPaddr[14-j] = '.';
}else if(j<3){
while(!(j==3)){
IPaddr[14-j]='0';
j++;
}
IPaddr[14-j] = '.';
}else if(j > 3 && j<7){
while(!(j==7)){
IPaddr[14-j]='0';
j++;
}
IPaddr[14-j] = '.';
}else if(j>7 && j<11){
while(!(j==11)){
IPaddr[14-j]='0';
j++;
}
IPaddr[14-j] = '.';
}
}else if(newhost[strlen(newhost)-(i+1)] == '\0'){ ///////////line33
while(!(j==15)){
IPaddr[14-j] = '0';
j++;
}
}else{
IPaddr[14-j] = newhost[strlen(newhost)-(i+1)];
}
}
printf("IPaddr: %s\n", IPaddr);
return IPaddr;
}
int main(int argc,char *argv[]){ /////////line48
char host[100] = {'\0'};
strcpy(host, "10.0.0.2");
char *new_IP;
new_IP = function(host); ////////////line52
printf("newIP:%s\n",new_IP);
free(new_IP);
return 0;
}
The code works and compiler outputs neither error nor warning. However, valgrind outputs (valgrind --tool=memcheck --leak-check=yes --track-origins=yes test
)
==22544== Conditional jump or move depends on uninitialised value(s)
==22544== at 0x8048547: function (test.c:11)
==22544== by 0x804872B: main (test.c:52)
==22544== Uninitialised value was created by a stack allocation
==22544== at 0x80486DB: main (test.c:48)
==22544==
==22544== Conditional jump or move depends on uninitialised value(s)
==22544== at 0x8048654: function (test.c:33)
==22544== by 0x804872B: main (test.c:52)
==22544== Uninitialised value was created by a stack allocation
==22544== at 0x80486DB: main (test.c:48)
Could anyone tell me how I can fix the code?
The trouble is that in the function, you are doing:
for (i=0, j=0; j < 15; i++, j++){
if ((newhost[strlen(newhost)-(i+1)] == '.')){
As you go through the loop, i becomes larger than the length of the initialized string, but I'd expect that to generate an 'out of bounds' error. However, because the variable in main() is not dynamically allocated, it may well be that valgrind can't help more. I recommend modifying main() to:
int main(int argc, char *argv[])
{
char *host = malloc(100);
if (host != 0)
{
strcpy(host, "10.0.0.2");
char *new_IP = function(host);
printf("newIP:%s\n", new_IP);
free(host);
free(new_IP);
}
return 0;
}
I expect valgrind to complain about more problems, in particular, out of bounds memory access.
Separately:
Since strlen(newhost) doesn't change while the function is running, you should compute it once, outside of the loop.
I'm not sure why you're using the if ((...)) notation. If it is a reflex action to avoid the compiler warning about using assignments in conditions, you're defeating the purpose of warning.
Would it be easier to parse the string into 4 numbers with sscanf() and then format them using sprintf()?
char *function(const char *newhost)
{
int o1, o2, o3, o4;
char *result = 0;
if (sscanf(newhost, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) == 4)
{
/* Should check that values are in range 0..255 */
result = malloc(16);
if (result != 0)
sprintf(result, "%.3d.%.3d.%.3d.%.3d", o1, o2, o3, o4);
}
return result;
}
Another alternative implementation of your function(), using string copying only:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *function(const char *newhost)
{
char *result = malloc(16);
if (result != 0)
{
strcpy(result, "000.000.000.000");
const char *beg = newhost;
for (int i = 0; i < 4; i++)
{
const char *end = strchr(beg, '.');
if (end == 0)
end = beg + strlen(beg);
memcpy(result + (i * 4) + 3 - (end - beg), beg, end - beg);
beg = end + 1;
}
}
return result;
}
int main(void)
{
char host[] = "10.0.0.2";
char *newhost = function(host);
printf("%s => %s\n", host, newhost);
free(newhost);
return 0;
}
This calculates how many digits are in each segment, and then copies it to the right place in the result buffer which has already been filled with zeroes and dots at the right places. It avoids all the magic numbers like 3, 7, 11 that litter the original code.
I'd also recommend a different interface to function, avoiding dynamic memory allocation:
void function(const char *oldhost, char *newhost)
We can debate about void vs int, but the calling function should supply the (known, fixed size) buffer where the output is to be written, so as to avoid having to do dynamic memory allocation. You'd use int if the function does any validation on the string it is given; otherwise, it can be void. The existing code mostly does not report an error if passed an erroneous IP address.
Related
I get this warning with gcc -std=gnu17 -Wall -Werror -Wshadow -O3 test.c:
In function ‘insertString’,
inlined from ‘replaceString’ at test.c:94:5,
inlined from ‘main’ at test.c:110:22:
test.c:69:5: error: ‘strncat’ output may be truncated copying between 0 and 77 bytes from a string of length 80 [-Werror=stringop-truncation]
strncat(source, buffer, STRING_SIZE - 1 - position - strlen(stringToInsert));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
Removing the do while loop (without any changes to the strncat() statement in question) from main() makes the warning go away.
What does the warning mean and why does it go away?
What changes should I incorporate in the code so that the above gcc command doesn't trigger the warning? The solution cannot simply disable the warning (with fe. #pragma statements). The solution has to use strncat() function.
Not important: This is for learning purposes, please be descriptive. The program solves an exercise 9 from chapter 9 of the book "Programming in C (4th Edition)" by Stephen G. Kochan.
The code:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define STRING_SIZE 81
int findString(const char strToSearch[], const char strSought[])
{
int strToSearchLength = strlen(strToSearch);
int strSoughtLength = strlen(strSought);
for (int i = 0; i <= strToSearchLength - 1; ++i)
{
if (strToSearch[i] == strSought[0])
{
int j = 0;
while (strToSearch[i+j] == strSought[j])
{
if (strSought[j+1] == '\0')
{
return i;
}
++j;
}
}
else if (i > strToSearchLength - strSoughtLength - 1)
{
return -1;
}
}
return -1;
}
bool removeString(char source[], const int start, const int nCharsToRemove)
{
int i, sourceLength = strlen(source);
if (start + nCharsToRemove > sourceLength || start < 0 || nCharsToRemove < 0)
{
printf("Error in function removeString(): invalid parameters.\n");
return false;
}
else
{
for (i = start; i < sourceLength; ++i)
{
source[i] = source[i + nCharsToRemove];
}
source[i] = '\0';
return true;
}
}
void insertString(char source[], const char stringToInsert[], const int position)
{
char buffer[STRING_SIZE];
int i = 0;
while (source[position + i] != '\0' && position + i < STRING_SIZE - 1)
{
buffer[i] = source[position + i];
++i;
}
buffer[i] = '\0';
source[position] = '\0';
strncat(source, stringToInsert, STRING_SIZE - 1 - position);
// THE STATEMENT MENTIONED IN THE WARNING:
strncat(source, buffer, STRING_SIZE - 1 - position - strlen(stringToInsert));
}
/* A function to replace the first occurence of the string s1
* inside the source string, if it exists, with the string s2
*/
bool replaceString(char source[], const char s1[], const char s2[])
{
int findString(const char strToSearch[], const char strSought[]);
bool removeString(char source[], const int start, const int nCharsToRemove);
void insertString(char source[], const char stringToInsert[], const int position);
int s1_position;
bool success;
// locate s1 inside source
s1_position = findString(source, s1);
if (s1_position == -1)
return false;
// remove s1 from source
success = removeString(source, s1_position, strlen(s1));
if (! success)
return false;
// insert s2 into source at the proper location
insertString(source, s2, s1_position);
return true;
}
int main(void)
{
char text[STRING_SIZE] = "1 is first*";
// uncommenting the following comment and discarding what follows it makes the warning go away
/*
replaceString(text, "is", "one");
printf("%s\n", text);
*/
bool stillFound;
do
stillFound = replaceString(text, "is", "one");
while (stillFound);
printf("%s\n", text);
return 0;
}
What does the warning mean
That is possible, potentially, that buffer will point to a string with 80 characters, but the length STRING_SIZE - 1 - position - strlen(stringToInsert) will be lower then 80. The warning was created to detect cases where not the whole source buffer would be copied to destination (ie. in a strcat(destination, source) call). It may potentially happen. In such case also the destination buffer will not be zero terminated.
why does it go away?
Different code makes compiler make different decisions. In this case compiler doesn't inline the calls, which most probably affects some static analysis done by the compiler. Adding static or attribute((always_inline)) to functions restores the warning. It's hard to answer "why" exactly - either the answer is too broad or too detailed. I believe inspect gcc sources or RTL output to know more.
What changes should I incorporate in the code so that the above gcc command doesn't trigger the warning?
Do not use strncat. Use memcpy. I think something along:
char *dest = &source[position]; // where we copy to
size_t destfree = STRING_SIZE - 1 - position; // how much space we have there
// helper macro
#define MIN(a, b) ((a)<(b)?(a):(b))
size_t to_copy = MIN(strlen(stringToInsert), destfree);
memcpy(dest, stringToInsert, to_copy);
dest += to_copy;
destfree -= to_copy;
to_copy = MIN(strlen(buffer), destfree);
memcpy(dest, buffer, to_copy);
dest += to_copy;
destfree -= to_copy;
dest[0] = '\0';
--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 am writing a grep program in C. In order to determine if the current line received should be printed to the screen, i use a function called reportLineMatchRec.
in this function i use another function named updateConExpWithStr2 to parse one of the strings used in reportLineMatchRec().
unfortunately, i keep getting valgrind errors saying there is uninitialized value being used inside this function, when using strlen() and strncat(), eventhough i initialized all values.
update: i updated the functions updateConExpWithStr1() and updateConExpWithStr2() so the gcc warning is gone and now i'm getting a single valgrind error (also updated below). i added to the valgrind check --track-origins=yes parameter which points out that the source for initialization problem is in the malloc inside fillRoundBrackets() inside commandParser module (added below). I still can't solve the problem.
the code:
the structs:
typedef enum {REGULAR, POINT, ROUND_BRACKETS, BRACKETS} partClassifier;
union expressionPartInfo {
char xy[2];
char *str1OrStr2;
char regularChar;
}expressionPartInfo;
typedef struct partInExpression
{
union expressionPartInfo expressionPartInfo ;
partClassifier partClassifier;
} partInExpression;
typedef struct parsedCommandStruct
{
char *expressionToSearch;
char *origExpressionToSearch;
char *concatenatedExpression;
int lengthOfOrigExpression;
int numOfExpressionParts;
bool a;
int aNum;
bool b;
bool c;
bool i;
bool n;
bool v;
bool x;
bool E;
struct partInExpression *arrayOfExpressionParts;
} parsedCommandStruct;
upadted matchInLine.c relevant functions:
void updateConExpWithStr1(parsedCommandStruct *parsedCommand, char **endOfString, int partIndex, char **orPtr,
int *str1size,char **orPtrcopy){
char *copyStr1OrStr2 = malloc(parsedCommand->lengthOfOrigExpression+1);
strcpy(copyStr1OrStr2, parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
*endOfString = parsedCommand->concatenatedExpression+strlen(parsedCommand->concatenatedExpression);
*orPtr = strstr(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, "|");
*orPtrcopy=(*orPtr)+1;
**orPtr = '\0';
*str1size = strlen(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2);
strcat(parsedCommand->concatenatedExpression, parsedCommand->arrayOfExpressionParts[partIndex].
expressionPartInfo.str1OrStr2);
strcpy(parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2, copyStr1OrStr2);
free(copyStr1OrStr2);
}
void updateConExpWithStr2(parsedCommandStruct *parsedCommand, int partIndex, char **orPtr,
int const*str1size, char **endOfString, char **orPtrcopy){
int str2size=0;
**endOfString = '\0';
str2size = strlen(*orPtrcopy);
strncat(parsedCommand->concatenatedExpression, *orPtrcopy, str2size);
}
void reportLineMatchRecE(int partIndex, lineInText *currentLineToCheck, parsedCommandStruct *parsedCommand,
int *linesAfterMatchCounterPtr, int *prevLinesCounter, int *matchFlag){
int j=0; char *orPtr = NULL; int str1size = 0; char *endOfString = NULL; char *orPtrcopy = NULL;
while(partIndex < parsedCommand->numOfExpressionParts){
if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == REGULAR) {
updateConExpWithRegChr(parsedCommand, &partIndex);
}
else if (parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == POINT){
for (j = ASCII_LOWEST_CHAR; j < ASCII_HIGHEST_CHAR+1; j++) {
updateConExpWithChr(j, parsedCommand, &endOfString);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
*endOfString='\0';
}
return;
}
else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == BRACKETS){
for (j = parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[0];
j < parsedCommand->arrayOfExpressionParts[partIndex].expressionPartInfo.xy[1]+1; j++) {
updateConExpWithChr(j, parsedCommand, &endOfString);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
*endOfString='\0';
}
return;
}
else if(parsedCommand->arrayOfExpressionParts[partIndex].partClassifier == ROUND_BRACKETS){
updateConExpWithStr1(parsedCommand, &endOfString, partIndex, &orPtr ,&str1size, &orPtrcopy);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
updateConExpWithStr2(parsedCommand, partIndex, &orPtr, &str1size, &endOfString, &orPtrcopy);
reportLineMatchRec(partIndex+1, currentLineToCheck, parsedCommand, linesAfterMatchCounterPtr,
prevLinesCounter, matchFlag);
return;
}
}
if(partIndex == parsedCommand->numOfExpressionParts){
strcpy(parsedCommand->expressionToSearch, parsedCommand->concatenatedExpression);
reportLineMatch(currentLineToCheck, *parsedCommand, linesAfterMatchCounterPtr, prevLinesCounter, matchFlag);
return;
}
}
commandParser.c relevant functions:
int fillRoundBrackets(parsedCommandStruct *parsedCommand, int indexOfParts, char *str1OrStr2){
parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = ROUND_BRACKETS;
char *placeOfClosingBracket = strstr(str1OrStr2, ")");
int str12Size = placeOfClosingBracket-str1OrStr2 - 1;
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = malloc(200);//str12Size+1);
strncpy(parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2, str1OrStr2+1, str12Size);
return str12Size+1;
}
void buildArrayOfExpressionParts(parsedCommandStruct *parsedCommand){
int numOfParts = computeNumOfParts(parsedCommand->expressionToSearch); int i=0, indexOfParts=0;
parsedCommand->arrayOfExpressionParts = NULL;
parsedCommand->arrayOfExpressionParts = malloc(numOfParts * sizeof(partInExpression));
for(i=0; i<(int)strlen(parsedCommand->expressionToSearch); i++)
{
if(parsedCommand->expressionToSearch[i] == '.')
{
parsedCommand->arrayOfExpressionParts[indexOfParts].partClassifier = POINT;
}
else if(parsedCommand->expressionToSearch[i] == '[')
{
fillBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1],
parsedCommand->expressionToSearch[i+3]);
i=i+4;
}
else if(parsedCommand->expressionToSearch[i] == '(') {
parsedCommand->arrayOfExpressionParts[indexOfParts].expressionPartInfo.str1OrStr2 = NULL;
i = i + fillRoundBrackets(parsedCommand, indexOfParts, parsedCommand->expressionToSearch + i);
}
else if(parsedCommand->expressionToSearch[i] == '\\')
{
fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i+1]);
i=i+1;
}
else {
fillRegularChar(parsedCommand, indexOfParts, parsedCommand->expressionToSearch[i]);
}
indexOfParts++;
}
}
void createAndFillCommand(int argc, char *argv[], parsedCommandStruct **parsedCommand) {
int indexOfExpressionArg = INITIALIZED_VALUE;
indexOfExpressionArg = searchExpressionArgumentIndex(argc, argv);
*parsedCommand = (parsedCommandStruct *) malloc(sizeof(struct parsedCommandStruct));
initializeCommandArgs(parsedCommand);
(*parsedCommand)->expressionToSearch = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->expressionToSearch, argv[indexOfExpressionArg]);
(*parsedCommand)->origExpressionToSearch = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->origExpressionToSearch, argv[indexOfExpressionArg]);
(*parsedCommand)->lengthOfOrigExpression = strlen((*parsedCommand)->expressionToSearch); // delete?
(*parsedCommand)->numOfExpressionParts = computeNumOfParts((*parsedCommand)->expressionToSearch);
updateArgumentsOfCommandStruct(argc, argv, *parsedCommand);
if((*parsedCommand)->E){
buildArrayOfExpressionParts(*parsedCommand);
(*parsedCommand)->concatenatedExpression = (char *)malloc(strlen(argv[indexOfExpressionArg])+1);
strcpy((*parsedCommand)->concatenatedExpression, "");
}
}
main.c:
void receiveAndExecute(parsedCommandStruct *parsedCommand, FILE **stream)
{
ssize_t lineSize = INITIALIZED_VALUE; int matchFlag = 0;
lineInText *currentLine = NULL;
int lineIndex = FIRST_LINE_INDEX, counterForC = INITIALIZED_VALUE,
linesAfterMatchCounter = INITIALIZED_VALUE, sumOfBytes = INITIALIZED_VALUE, prevLinesCounter = INITIALIZED_VALUE;
currentLine = malloc(sizeof *currentLine);
initializeCurrentLine(currentLine);
while (1)
{
readLine(stream, &lineSize, currentLine);
FillLineStruct(currentLine, lineIndex, sumOfBytes);
sumOfBytes = (int)lineSize + sumOfBytes;
lineIndex++;
initializeConcatinateExp(parsedCommand);
if(lineSize<0)
break;
reportLineMatchRec(0, currentLine, parsedCommand, &linesAfterMatchCounter, &prevLinesCounter, &matchFlag);
printLineToOutput(currentLine, parsedCommand, &counterForC, false, &linesAfterMatchCounter,
&prevLinesCounter, &matchFlag);
}
printLineToOutput(currentLine, parsedCommand, &counterForC, true, NULL, NULL, NULL);
freeLine(¤tLine);
}
int main(int argc, char* argv[])
{
parsedCommandStruct *parsedCommand = NULL;
FILE *filePtr = NULL;
bool useFile = false;
useFile = isUsingFile(argc, argv);
createAndFillCommand(argc, argv, &parsedCommand);
if (useFile)
{
filePtr = openFile(argv[argc-1]);
receiveAndExecute(parsedCommand, &filePtr);
fclose(filePtr);
}
else
{
receiveAndExecute(parsedCommand, &stdin);
}
freeParsedCommandStruct(parsedCommand);
free(parsedCommand);
return 0;
}
updated valgrind report
==7832== Conditional jump or move depends on uninitialised value(s)
==7832== at 0x4C2E1EB: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832== by 0x401BF7: updateConExpWithStr1 (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x401F48: reportLineMatchRecE (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x4020A4: reportLineMatchRec (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x402280: receiveAndExecute (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x402377: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== Uninitialised value was created by a heap allocation
==7832== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==7832== by 0x40108C: fillRoundBrackets (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x401218: buildArrayOfExpressionParts (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x40142D: createAndFillCommand (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832== by 0x40233B: main (in /specific/a/home/cc/students/csguests/nadavbarkol/c_lab/ex2/my_grep)
==7832==
Moving this from the comments to an Answer.
This code is exceptionally dense and is really hard to paste into a comment, so I've added some whitespace, and I see you've already removed unnecessary items such as casting the return of malloc().
This is all about compiler warnings, including one you are not getting.
In general, compiler warnings are not things you fix, they are things you understand. Once you understand what it's telling you, the fix is usually free and obvious.
warning: assignment makes pointer from integer without a cast
The compiler is telling you that in the marked line below, one side is an integer and one side is a pointer - isn't it pretty clear what's going on here:
void updateConExpWithStr1(parsedCommandStruct parsedCommand, char **endOfString,
int partIndex, char **orPtr, int *str1size) {
*endOfString = parsedCommand.concatenatedExpression
+ strlen(parsedCommand.concatenatedExpression);
*orPtr = strstr(
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
"|");
// THIS NEXT LINE IS WRONG
str1size = *orPtr - parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2;
strncat(parsedCommand.concatenatedExpression,
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
(size_t)str1size); // THIS LINE TOO
}
str1size is not a size, it's a pointer to a size, so this is all kinds of problematic.
The code as written stores an integer value where a pointer should be, and that means the caller is not seeing the size passed back. That's probably a bug.
Then the later line marked as a bug happens to function correctly even though it's two kinds of wrong. strncat() is expecting a size as the third parameter, but it's given a pointer cast to an integer, which is never the right thing for a size, except this time because the integer was improperly stored as a pointer. How about that!
But just adding a * only solves the technical problem, it's better to avoid this in the first place with good naming conventions. What if your function had been:
void updateConExpWithStr1(parsedCommandStruct parsedCommand, char **endOfString,
int partIndex, char **orPtr, int *pStr1size) {
...
*pStr1size = blah // integral result
strncat(parsedCommand.concatenatedExpression,
parsedCommand.arrayOfExpressionParts[partIndex].expressionPartInfo.str1OrStr2,
*pStr1size);
}
Here we not only store the result properly, but by changing the name to remind you that it's a pointer, it makes it easier for you tell just by looking that this is not just an integral size.
The lesson here, I hope, is that you should take compiler warnings seriously with a goal of understanding them, not just making them go away.
When you put (size_t) str1size in the call to strncat(), I'm pretty confident you were doing this to silence a compiler warning that you didn't understand, and that's dangerous.
By adding the cast, you told the compiler "trust me", so this was a bug that went into hiding in plain sight (I didn't notice it until I was mostly done writing this post).
This is a discipline that all good C programmers develop: to crave compiler warnings, and to understand every one of them. Always turn them on to the max, and always include them in any SO post.
I have a problem with this piece of code that I modified many times (but the error always appeared):
It seems it has an error in freeing the last index of "filter"
char** read_and_filter(int fd) {
char buf[MAXLENGTH];
char **bufs=NULL;
char ch;
int j = 0, len = 0, t = 0;
while (!t && read(fd,&ch,1) == 1) {
switch (ch) {
case '\n':
t = 1;
case ' ':
bufs = realloc(bufs, (j+1)*sizeof(char*));
bufs[j++] = strndup(buf,len);
memset(buf,0,len);
len = 0;
break;
default:
buf[len++] = ch;
}
}
bufs[j] = 0;
return bufs;
}
int main(int argc, char **argv) {
char **filter;
int i,fd = open("input.txt",O_RDONLY);
filter = read_and_filter(fd);
for(i = 0; filter[i]; i++) {
printf("%s\n",filter[i]);
free(filter[i]);
}
return 0;
}
Here is the output:
0x1521030
HOME
0x1521050
2
0x1521070
A
0x1521010
8
0x15210c0
D
*** Error in `./test': free(): invalid pointer: 0x00000000015210c0 ***
I also tried to debug it with valgrind (it says me that the allocator tries to free 9 byte while the sum of characters is 8, strange no?) and gdb but nothing worked.
The first line of input.txt is "HOME 2 A 8 D\n"
The first time these lines are executed
bufs = realloc(bufs, (j+1)*sizeof(char*));
bufs[j++] = strndup(buf,len);
you obtain memory for 1 pointer (j was 0). This leaves no space for the closing NULL you write at the end of the function with
bufs[j] = 0;
so you are writing beyond the allocated memory, thus have undefined behaviour. Similarly each time you extend the buffer length.
Your bufs[j] = 0; at the end of read_and_filter writes into non-allocated memory. You never realloc-ed your bufs for that extra 0.
Memory leak is occurring from two places - strdup and the realloc
One answer is to make an initial allocation of memory for the buffer in main, using malloc and then pass a pointer to the allocated memory to the function. The function can then realloc the buffer, and copy data into it.
On return from the function, main can access the data directly from the buffer as it has a valid pointer to it, and then can free that memory before closing.
According to valgrind, the following has no memory loss.
void read_and_filter(int fd, char **bufs) {
char buf[100];
char ch;
int j = 0, len = 0, t = 0;
while (!t && read(fd,&ch,1) == 1) {
switch (ch) {
case '\n':
t = 1;
case ' ':
*bufs = realloc(*bufs, (j + 2)*sizeof(char*));
strncpy(bufs[j++], buf, len);
memset(buf,0,len);
len = 0;
break;
default:
buf[len++] = ch;
}
}
bufs[j] = 0;
return;
}
int main(int argc, char **argv) {
char *bptr = malloc(1);
int fd = open("input.txt", O_RDONLY);
read_and_filter(fd, &bptr);
printf("%s\n", bptr);
free(bptr);
return 0;
However I cannot be sure that this fully replicates the OP's intended functionality, but the overall approach does deal with the memory issues.
I'm trying to code the function solving the following problem (which is irrellevant, I'm describing it in order to describe the code that follows):
Given a word and a rule in form: "lhs->rhs" where word = lhs ^ suffix, output rhs ^ suffix, so for example:
If a word is "input" and a rule is "in->out" the function would return the word "output", or NULL if the rule cannot be used for the word.
There is a twist though: "lhs" might also contain digit variables (in addition to letters), e. g. "01->10", in this case, that rule would convert "niput" to "input" when used on "niput" (so digits correspond to letters standing at certain positions).
Here's the code:
#include <wchar.h>
#include <stdlib.h>
#include <stdio.h>
#define MAX_WORD_SIZE 101
wchar_t *transform_by_rule(wchar_t *word, wchar_t *lhs, wchar_t *rhs)
{
int i;
long int wint;
int lhs_len = wcslen(lhs);
int rhs_len = wcslen(rhs);
int word_len = wcslen(word);
// Initial check - does lhs fit to word
if (word_len < lhs_len)
return NULL;
for (i = 0; i < lhs_len; i++)
{
if (iswdigit(lhs[i]))
continue;
else
{
if (lhs[i] != word[i])
return NULL;
}
}
wchar_t *result =
malloc((rhs_len + 1) * sizeof(wchar_t));
wchar_t int_wchar_map[10];
for (i = 0; i < lhs_len; i++)
{
if (iswdigit(lhs[i]))
{
wint = lhs[i] - L'0';
int_wchar_map[wint] = word[i];
}
}
for (i = 0; i < rhs_len; i++)
{
if (iswdigit(rhs[i]))
{
wint = rhs[i] - L'0';
result[i] = int_wchar_map[wint];
}
else
{
result[i] = rhs[i];
}
}
return result;
}
int main()
{
wchar_t word[MAX_WORD_SIZE];
wchar_t lhs[MAX_WORD_SIZE];
wchar_t rhs[MAX_WORD_SIZE];
wscanf(L"%ls", word);
wscanf(L"%ls", lhs);
wscanf(L"%ls", rhs);
wchar_t *result = transform_by_rule(word, lhs, rhs);
if (result != NULL)
{
wprintf(L"%ls\n", result); // line 67
free(result);
}
else
{
puts("Rule doesn't fit to word.");
}
return 0;
}
Here's the problem. When run under valgrind for input "a" (word), "a" (lhs), "b" (rhs), the valgrind outputs error:
==6094== Conditional jump or move depends on uninitialised value(s)
==6094== at 0x4C30E19: wcslen (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==6094== by 0x4E8C3F6: vfwprintf (in /usr/lib64/libc-2.20.so)
==6094== by 0x4EA7448: wprintf (in /usr/lib64/libc-2.20.so)
==6094== by 0x4009AA: main (main.c:67)
I don't see any problem with my code. Is this a problem with wprintf()?
result is not zero-terminated before returning from transform_by_rule(). Thus, when calling wprintf() on its return value, wprintf() may read out-of-bound since it may not encounter terminating wide character within the allocated memory block.
Use wchar_t *result = calloc(rhs_len + 1, sizeof(wchar_t));, and you get correctly terminated string automatically if you are sure that you don't write over boundary inside transform_by_rule().