Why appear "#" added when copy chars in C - c

I'm creating a program in C, which receive a file and reverses each line like this:
$ cat file
Line 1
Line 2!
Line_3
$ ./reverse < file
1 eniL
!2 eniL
3_eniL
But I get an error and I don't know why.
In the program, I made a loop which:
Read a line from stdin to a string of 2048 chars.
Get the strlen from the read line and made a new string.
Copy, char by char, the characters of the string to the new string, in reverse order.
But, running the program, sometimes copy a char and other simbols (#) getting something like this:
http://i.stack.imgur.com/G8VTx.png
Some strings get # simbols depending on the length. Here, another example:
http://i.stack.imgur.com/1UKdL.png
The files are in us-ansii.
The code of the program is:
#include <stdio.h>
#include <string.h>
#include <sysexits.h>
#include <stdbool.h>
int main(int argc, char *argv[]){
char string[2048];
bool final = false;
while(!final){
fgets(string,2048,stdin); // Read line
if(feof(stdin))
final=true;
else{
int length;
length = (string[strlen(string)-1] == '\n') ? strlen(string)-1 : strlen(string);
char reverseStr[length];
// Loop
int count = length;
for(int i=0;i<length;i++){
reverseStr[i]=string[count-1];
count--;
}
printf("%s\n",reverseStr);
}
}
}
I have tried changing the loop:
for(int i=0;i<length;i++){
reverseStr[count-1]=string[i];
count--;
}
Whit pointers:
for(int i=0;i<length;i++){
char * pr = $reverseStr[count-1];
*pr=string[i];
count--;
}
# Symbol use to appear in the same position.
"Febrero" gets "orerbeF"
"Febrerol" gets "lorerbeF#"
"Febreroll" gets "llorerbe#" (lose the "F")
Here an image of the gdb:
When program is reversing second line "Febreroll"
reverseStr is "llorer" (in $12)
In the next iteration:
reverseStr is "llorerb" (in $14)
In the next iteration, program copy an "e" and more things:
reverseStr is "llorerbe\221\b#" (in $16)
GDB IMAGE IN A COMENT↓↓↓

This occurs because the code does not take care to insure there is a NUL character at the termination. The # happens to appear in the (uninitialized) buffer at the end, then presumably a random NUL is after that.
To fix this, do something like:
for(int i=0;i<length;i++){
reverseStr[i]=string[count-1];
count--;
}
reverseStr[length] = '\000'; // I added this.

You have the length stored as a separate count rather than a NUL terminator. So use the length in the format string.
printf("%*s\n", length, reverseStr);

Related

Reuse Array of Char Pointers

Suppose I want to "reuse" an array of char pointers, like in the following program that loops files given in the argument list, loops the lines in the file, adds them to a dynamically allocated array, then prints it:
// includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// globals
int progReturn = 0;
int globalLineCounter = 0;
////// main
int main(int argc, char *argv[]) {
FILE *fp;
int i;
// iterate files. first arg is the program name
for (i = 1; i < argc; i++) {
fp = fopen(argv[i], "r");
if (fp == NULL) {
fprintf(stderr, "The file '%s' did not exist.\n", argv[i]);
progReturn = 1;
} else {
// read lines from the file
char line[256];
// THE PROBLEM: I'd like to completely clear this array.
char **lines = malloc(16 * sizeof(char*));
// iterate lines
int fileLineCounter = 0;
while (fgets(line, sizeof(line), fp)) {
// remove newline
strtok(line, "\n");
// add lines to array
lines[globalLineCounter] = malloc(256 * sizeof(char));
strcpy(lines[globalLineCounter], line);
//printf("%s\n", lines[globalLineCounter]); // tester
fileLineCounter++;
globalLineCounter++;
}
// all lines read
printf("The file '%s' had %d lines.\n", argv[i], fileLineCounter);
// print the array
int j=0;
for (j=0; j<fileLineCounter; j++) {
// PROBLEM: Garbage from the second file when it prints here.
printf("%s\n", lines[j]);
}
// delete lines, delete file
memset(lines, 0, sizeof(*lines));
fclose(fp);
}
}
// all files read
return progReturn;
}
On the first file, everything works with no problems. On the second file, when I print the array, It shows unprintable characters, and some of the lines from the first file.
What could be causing this issue? Am I not fully clearing **lines?
EDIT: example input and output:
input file foo:
This is a test
of the lineSort program
in order to
test its capabilities.
Lots of whitespace too!
aaa
bbb
cccccc
aaa
ggggg
hhhhh
fffff
eeeee
ddddd
ppppp
input file bar:
aaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbb
zzzzzzzzzzzzzzzzz
ccccccccccccccccc
yyyyyyyyyyyyyyyyy
output for sortLine foo bar:
The file 'foo' had 20 lines.
cccccc
Lots of whitespace too!
This is a test
aaa
aaa
bbb
ddddd
eeeee
fffff
ggggg
hhhhh
in order to
of the lineSort program
ppppp
test its capabilities.
The file 'bar' had 5 lines.
(x▒▒
(x▒▒
Lots of whitespace too!
in order to
test its capabilities.
strcpy(lines[globalLineCounter], line);
This looks like your main problem. globalLineCounter keeps increasing across all input files.
Let's say your first input file contains 10 lines and your second file 5 lines. Then your code will create a dynamic array (of dynamic arrays) and store the lines from the first file in elements 0 .. 9 (and then print them). You never free any of the allocated memory, so it all leaks at the end of the loop.
For the second file, you create another dynamic array. You store the 5 lines from the second file in elements 10 .. 14 (via globalLineCounter), but then print elements 0 .. 4 (fileLineCounter). Those elements are uninitialized and contain garbage.
Move the char **lines initialization outside of the for loop.
Rename the index counter i to something different.
Repeatedly calling lines[i] = malloc(...) on multiple files will cause a memory leak. Think about using free inside the for loop, or move this part of the initialization outside the for loop.

C - Replacing words

My goal here is to read text from a file redirected from stdin, then replace certain argv passed words with the word "Replaced".
For example, if I run:
$ ./a.exe line < input.txt
where input.txt is "Test line one", at the end I should print "Test Replaced one."
I'm not quite sure where my code is going wrong, sometimes I get segmentation fault, and I'm also not sure how I would go about printing the newOut string, or if I even need one.
As a side note, if I was reading using fgets, what if the 59th character started "li" then as it started reading again as the 0th index for the next read command, "ne". Wouldn't that not count as one string for strstr to search?
Any help is appreciated, thanks
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char** argv) {
char fileRead[60];
char newOut[];
while (!feof(stdin)){
fgets(fileRead,60,stdin); //read file 60 characters at a time
if (strstr(fileRead,argv[1])){ // if argumentv[1] is contained in fileRead
strncpy(newOut, fileRead, strlen(argv[1])); // replace
}
}
return (0);
}
As I observed in the comments to your previous question, C — A better method for replacing:
An obvious suggestion is to read whole lines with fgets() and then search those (maybe with strstr()) to find the word to be replaced, and then print the material before the word and the replacement text before resuming the search from after the matched word in the line (so [given "test" as argv[1]] a line containing "testing, 1, 2, 3, tested!" ends up as "Replaced!ing, 1, 2, 3, Replaced!ed!".
This is a rather straight-forward implementation of the described algorithm.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
assert(argc > 1);
char fileRead[4096]; /* Show me a desktop computer where this causes trouble! */
char replace[] = "Replaced!";
size_t word_len = strlen(argv[1]);
while (fgets(fileRead, sizeof(fileRead), stdin) != 0)
{
char *start = fileRead;
char *word_at;
while ((word_at = strstr(start, argv[1])) != 0)
{
printf("%.*s%s", (int)(word_at - start), start, replace);
start = word_at + word_len;
}
printf("%s", start);
}
return (0);
}
Note that the position of the assert() makes this C99 code; place it after the definition of word_len and it becomes C89 code.

Can anyone explain/show to me how this code gets an input, as well as how this code is vulnerable to an arc injection by buffer overflow?

Can anyone tell me how this code gets an input, as well as how this code is vulnerable to an arc injection by buffer overflow??
#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>
Sets Size to 65
enum {SIZE = 65};
Variable that I'm trying to change
int True = 0;
char name[SIZE];
FILE *f;
int i = 0;
How does this read from a file?
void read(char *s) {
int c;
char buffer[SIZE];
for (;;)
{
c = getchar();
if ((c == EOF) || (c == '\n'))
break;
buffer[i] = c;
i++;
}
buffer[i] = '\0';
for (i = 0; i < SIZE; i++)
s[i] = buffer[i];
}
int main(void) {
read(name);
if (!True)
printf("%s: You are a hacker\n", name);
else
printf("%s: You are not a hacker\n", name);
How can you not use a return value?
exit(0);
}
This code gets an input through 'stdin;. By default, this would be done by keyboard input. However, it may also possible to 'pipe' the content of a file into 'stdin' when loading the program on the command line.
This code is vulnerable to an arc injection by buffer overflow. Specifically, if more than 65 characters are copied into 'name' array, the value of 'True' will be overwritten. Most likely, this will change the value of 'True' to a non-zero value. This will reverse the 'if (!True)' and cause the line 'printf("%s: You are a hacker\n", name);' to execute.
This is the line that can cause buffer overflow
buffer[i] = c;
since you are not checking whether i is within bounds before that statement.
When that happens, you are most likely going to override the part of stack frame that contains code since there is no other function variable after buffer.
I ran the program by piping the contents of a file that contains 100 As in it to the stdin of the program. I got the following message, which confirmed my suspicion.
>> cat test-121.in | ./test-121
*** stack smashing detected ***: ./test-121 terminated
Aborted
I don't see how that could change the value of True at all.
BTW, you have:
if (!True)
printf("%s: You are a hacker\n", name);
else
printf("%s: You are not a hacker\n", name);
did you mean if (True)?? You have initialized True to 0.
Update
You asked: How can you not use a return value?
Answer: return statement is optional for main. Here's a section of the description of main from http://en.cppreference.com/w/cpp/language/main_function.
(4) The body of the main function does not need to contain the return statement: if control reaches the end of main without encountering a return statement, the effect is that of executing return 0;

Something wrong while using crypt function in C

I am using the crypt function in C, where I am giving the command line input an encrypted word. I use the words in /usr/share/dict/words and encrypt them using the crypt function and then compare the encrypted output of the crypt function with the command line input. If the words are the same, then I give out the non-encrypted code as the output using a printf statement.
The code is given below.
#include<stdio.h>
#define _XOPEN_SOURCE
#include<unistd.h>
#include<cs50.h>
#include<string.h>
int
main(int argc, string argv[]){
char line[80];
string crypto;
if(argc>2||argc<2)
{
printf("ERROR. Enter only one crypt");
return 1;
}
string crypti=argv[1];
FILE *fr;
string as;
fr=fopen("/usr/share/dict/words","r");
if(!fr)
{
printf("File can't be read");
exit(-1);
}
while(fgets(line,80,fr)!=NULL)
{
as=crypt(line,"50");
if(strcmp(as,crypti)==0)
{
printf("%s",line);
break;
}
}
fclose(fr);
}
The code seems to work fine just for 1 input i.e when I give "./a.out 50q.zrL5e0Sak"(without quotes). However, if I use any other input for the crypt, the code seems to fail. Another example for password:encrypted password is abaca:50TZxhJSbeG1I. The word abaca is present in the list but fails to identify. I am not able to fix this code to work for all inputs.
Add the following snippet to the beginning of while (fgets...) body:
size_t len = strlen(line);
if (len)
line[len-1]='\0';
There is usually a newline \n (when it was read) in the end of the buffer read by fgets.
Your original code works with "password" because only 8 first characters of the key are actually used by crypt. It would work with any word of length 8 or more as well.
Also, make sure that the output is flushed after you print the result, by adding a newline to your format string or (if you don't want to output an extra newline) calling fflush(stdout):
printf("%s\n",line);
/* or */
printf("%s",line);
fflush(stdout);

Having issues with counting the number of bytes in use by files in a folder. Getting a segfault error

I am currently trying to count the number of bytes consumed by files in a certain directory. It recursively goes through all the folders on the current directory and counts the bytes of the files.
When I recursively call the function rec_bytes, I print off "Go in"... but when it returns the value... It segfaults.
I labeled the problematic line in the code below.
I think the problem has to do with open/closing directories.
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
int rec_Bytes(char path[])
{
int bytesSum = 0;
printf("PathX %s\n", path);
DIR *mydir = opendir(path); // Look in current directory
struct dirent *entry = NULL;
while((entry = readdir(mydir))) /* If we get EOF, the expression is 0 and
* the loop stops. */
{
if (!isDir(entry->d_name)) // Check to see if the entry is a directory of a file
{
char tempPath[] = "";
strcat(tempPath, path);
strcat(tempPath,"/");
strcat(tempPath,entry->d_name);
int tempSum = fileSize(tempPath); // Get file size
bytesSum += tempSum; // Add to sum
printf("%s\t%d\n", entry->d_name, tempSum);
}
else // The current entry is a directory
{
if ((strcmp((entry->d_name),"..") != 0) && (strcmp((entry->d_name),".")) != 0)
{
printf("Directory%s\n", entry->d_name);
char tempPath[] = "";
strcat(tempPath, path);
strcat(tempPath,"/");
strcat(tempPath,entry->d_name);
printf("Go in\n");
int tempSum = rec_Bytes(tempPath); <<<<<< Get segmentation fault here.
printf("Come Out%d\n", tempSum);
bytesSum += tempSum;
printf("%s\t%d\n", entry->d_name, tempSum);
}
}
}
closedir(mydir);
printf("XXXX\t%s\t%d\n", path, bytesSum);
return bytesSum;
}
// Thanks to : http://cboard.cprogramming.com/cplusplus-programming/117431-how-tell-if-file-directory.html
int isDir(const char* target)
{
struct stat statbuf;
stat(target, &statbuf);
return S_ISDIR(statbuf.st_mode);
}
Your problem is with lines like this...
char tempPath[] = "";
This will allocate a buffer with one byte, that byte being a null character. There is no room in that buffer for any longer string.
Basically, C does not have dynamically resizable strings. It has null terminated strings that live within fixed-size arrays of characters. This creates an issue when you won't know the length of the string until you've finished building it, of course.
Try something like...
char tempPath[5000] = "";
as a quick fix. Also, look up strncat - it's less likely to segfault. There's a printf variant as well, but I use too much C++ these days.
EDIT
Actually, the segfault is probably due to those strcats and printfs corrupting the stack. The segfault is probably when a function tries to return. The basic issue is the too-small string buffers thing, though.
Whoops!
The real quick fix is...
char tempPath[5000];
tempPath [0] = 0;
Otherwise, it won't always get initialised to an empty string when you expect it to.

Resources