gcc C ***stack smashing detected*** array - c

The line of code causing the problem is
char command_tb_temp[][1000]={"gcc -Wall ","-o3 -ftree-ccp -fno-align-jumps "," Scripts/*.c -o output -lm && time -f \"%e\" -o TB.log ./output 1.dat"};
When the same code is written by giving only 1 optimizing option like below, It does not return any errors.
char command_tb_temp[][1000]={"gcc -Wall ","-o3 -ftree-ccp "," Scripts/*.c -o output -lm && time -f \"%e\" -o TB.log ./output 1.dat"};
Please help me resolve this issue. Any help is highly appreciated.
Thankyou.
Heres the whole function..
int findtb(int flag)
{
printf("debug -1-1-1");
char command_tb_temp[][1000]={"gcc -Wall ","-o3 -ftree-ccp -fno-align-jumps "," Scripts/*.c -o output -lm && time -f \"%e\" -o TB.log ./output 1.dat"};
char command_tb[]="",line[100];
if(var[initial].exetime>0.00&&flag==1)
{
if(var[initial].rip<0.00)
strcat(finalop,var[initial].name);
else
return 0;
}
strcpy(command_tb_temp[1],finalop);
//strcat(command_tb_temp[1]," -ftree-ccp ");
for(int i=0;i<3;i++)
strcat(command_tb,command_tb_temp[i]);
printf("***** %s ****",command_tb);
system(command_tb);
fp=fopen("TB.log","r");
fscanf(fp,"%s",line);
tb=atof(line);
printf("\nTb=%f\n",tb);
fclose(fp);
return 1;
}
The error is...
*** stack smashing detected ***: ./3 terminated

char command_tb[] = "" defines a character array of size 1, containing just a terminating null character.
strcat(command_tb,command_tb_temp[i]); then writes data to it.
But it writes more data than it can hold, thus corrupting other parts of memory.
You should make it large enough.
Also, it's advisable not to use strcat, strcpy, as they can easily exceed the buffer. Better use strncpy at others, which get the buffer size and won't write more. It's still your responsibility to provide the right size.
But beware of strncat - the meaning of its size parameter is misleading, so read its documentation with care, or just avoid using it.

Related

How to "execute" Makefile in Ubuntu to run C program that reads from stdin and outputs to stdout/stderr

I'm working on a homework problem that reads characters from an input.txt file and outputs the first word read into an output.txt, the second into an error.txt, then the third to output.txt again, and so on until it reaches the end of the input.txt file.
I should note this is all done using Ubuntu 18.04
I was given a custom Makefile and had to edit a C program called split.c which would take the input.txt through the stdin and output to stdout/stderr. I can write my C program and have it listed below, however I can't test if it's correct because I do not understand how to run make, how to set up my files correctly and if my C program is correctly reading and outputing as it should.
I have tried running the 'make' command in the terminal but I receive:
make: No targets specified and no makefile found. Stop.
I have looked at countless articles on Linux, making 'make files', etc. but I don't know what I'm being asked or what to do so I am at a stand still. Guidance is greatly appreciated!
The custom makefile looks like this and is called Makefile.dat:
CC=gcc
CFLAGS=-Wall
EXEC=split
SRC=$(EXEC).c
TEXT_DIR=test
TEST_INPUT=$(TEST_DIR)/input.txt
OUT=$(TEST_DIR)/stdout.txt
ERR=$(TEST_DIR)/stderr.txt
EXP_OUT=$(TEST_DIR)/output.txt
EXP_ERR=$(TEST_DIR)/error.txt
TEST_REQS=$(TEST_INPUT) $(EXP_OUT) $(EXP_ERR)
DIFF=diff -bBqa
all: $(EXEC)
$(EXEC): $(SRC)
$(CC) $(CFLAGS) $(SRC) -o $(EXEC)
.PHONY: test
test: $(TEST_REQS) $(EXEC)
./$(EXEC) < $(TEST_INPUT) > $(OUT) 2> $(ERR)
$(DIFF) $(EXP_OUT) $(OUT)
$(DIFF) $(EXP_ERR) $(ERR)
echo TEST PASSED!
.PHONY: clean
clean:
$(RM) $(EXEC)
And my C program looks like this and is called split.c:
#include <stdio.h>
int main(){
int input;
// keep getting characters until end-of-file
while((input = fgetc(stdin)) != EOF){
// prints to stdout
printf(stdout, "%d", input);
if(input = " ")
printf("\n"); // encounters whitespace so print new line
// prints to stderr
printf(stderr, "%d", input);
if(input = " ")
printf("\n"); // encounters whitespace so print new line
}
return 0;
}
With the idea being that it takes the input file, then it'll print each letter into it's respective file, and if it encounters a space it'll print a new line before adding the next character into the other file.
For example:
input.txt has the text:
"How do I do this stuff?"
output.txt will have:
How
I
this
error.txt will have:
do
do
stuff?
I fully expect that my C program is missing code. My thinking when writing the program was, print to stdout, then if whitespace is encounterd, print a new line, then begin printing to stderr, and repeat until EOF is reached.
Either rename Makefile.dat to Makefile, like this:
mv Makefile.dat Makefile
make
or run make with the -f option and an argument of your Makefile:
make -f Makefile.dat
Make sure all your files (split.c, test/input.txt, Makefile) are present in the same directory as the Makefile, otherwise this won't work.
Note some issues with your C code:
if(input = " ")
is wrong. First of all, it's assigning a string with a space in it " " (which is a pointer to char) to input, instead of checking if input is a space character.
To fix the issue, use this:
if(input == ' ')
in both cases.

C minimum bytes read

I'm curious why when reading less than 4 bytes from a file, the output is corrupted.
Here is my test file:
user#UnixVM:~/labs$ cat foo.txt
helloworld
And a simple program to read from the file:
int main()
{
int file=0;
if((file=open("foo.txt",O_RDONLY)) < -1)
return 1;
char buffer[11];
read(file,buffer,3);
printf("%s\n",buffer);
return 0;
}
The output is corrupted and may be different between executions:
user#UnixVM:~/labs$ gcc -Wall lab1_4.c -o lab1_4 ; ./lab1_4
hel2
user#UnixVM:~/labs$ gcc -Wall lab1_4.c -o lab1_4 ; ./lab1_4
helâ–’
But every time I make number of bytes to read greater or equal to 4 (read(file,buffer,4);), it works fine.
Your output is "corrupted" because buffer does not contain a NUL terminated C string. Read more about undefined behavior. Be scared (UB sometimes appears to work, and that might explain what you experiment).
So before your call to read add memset(buffer, 0, sizeof(buffer)) to clear your buffer. Or initialize it with char buffer[11] =""; (both are nearly equivalent and likely, with optimizations enabled e.g. gcc -O2, to generate the same machine code). Since your buffer is 11 bytes long and you read at most 3 bytes you'll then be sure that it is NUL terminated after the read.
Be sure to compile with all warnings and debug info (so gcc -Wall -Wextra -g lab1_4.c -o lab1_4 in your case). Read How to debug small programs
Read carefully the documentation of read(2) and of every function you are using. Notice the return count from read. You should test and use it.

Encoding Url In C With Line Breaks?

I've got this url encoder I found on the internet and made few small changes, however when ever I do something such as this:
char encodedWord[100];
const char* word = "Stack\nOverflow";
urlencode(encodedWord, word);
The output would be something like this:
"Stack0X8.51EE00001674P-1022Overflow" instead of x0A in between of Stack Overflow.
Why is it outputting that? I assume because of the "EE0000" part something went wrong with the char to number conversion.
How can I get my encoder to be much more friendly to special characters? i.e "\n,\r,\r".
The Function
int urlencode(char *dest, const char *src)
{
/* urlencode all non-alphanumeric characters in the C-string 'src'
store result in the C-string 'dest'
return the length of the url encoded C-string
*/
char *d;
int i;
for(i=0, d=dest; src[i]; i++) {
if(isalnum(src[i]) || isdigit(src[i])) {
*(d++) = src[i];
} else {
snprintf(d, 4, "%%%02X", src[i]);
d += 3;
}
}
*d = 0;
return d-dest;
}
System
Windows 10 32bit
Mingw32 (gcc 5.1.0)
Make File
#OBJS specifies which files to compile as part of the project
OBJS = $(wildcard ./src/*.c)
#CC specifies which compiler we're using
CC = gcc
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS =
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS =
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS = -Wall -Wl,-subsystem,console -std=c99
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lws2_32 -lwininet -s -lshlwapi
#OBJ_NAME specifies the name of our executable
OBJ_NAME = project
#This is the target that compiles our executable
all : clean build
build:
cls
$(CC) $(OBJS) $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) $(LINKER_FLAGS) -o $(OBJ_NAME)
clean:
del -f $(OBJ_NAME).exe
the urlencode function is working just fine, the problem is how you're printing the output. I was in the middle of writing
0X8.51EE00001674P-1022 is a hexadecimal floating point number, what you would expect to see from a %A printf specifier.
when it struck me that the correct output has %0A in that exact position. Which means that you're making the mistake of passing a non-constant string as the first parameter of printf. Don't do printf(encodedWord); you should be using printf("%s", encodedWord) instead.

check size of C type at build time

I want to establish build-time cross-language ABI compatibility with Waf. How would I go about checking the size of a type (or any arbitrary type-like checks), and recording it into the build configuration?
You can create a program which outputs that size. I saw this apporach on several ./configure files:
cat << EOF > test.c
#include <stdio.h>
int main ()
{
printf("int %d\n", sizeof(int));
return 0;
}
EOF
$(CC) test.c -o out
./out >> sizes
rm -f test.c out
Of course, with testing of erroneous cases and such.
Edit: See the waf documentation. Specially, read the run_c_code method. For saving the value of sizeof you can write to a file instead and read it from Python/Waf. Or, see the define_ret argument.

Valgrind reporting invalid write errors

This is more focused than my previous Valgrind question; I am trying to narrow down write and read errors when parsing command-line options:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/stat.h>
#include <string.h>
#include <locale.h>
#include <bzlib.h>
#include <zlib.h>
#include "starch.h"
#define BUFMAXLEN 1024
int main(int argc, char **argv) {
if (parseCommandLineInputs( &argc, &argv ) != 0)
exit(EXIT_FAILURE);
return 0;
}
int parseCommandLineInputs(int *argc, char ***argv) {
pid_t pid;
struct utsname uts;
char uniqTag[BUFMAXLEN];
if ((*argc == 1) || (*argc > 4)) {
printUsage();
return -1;
}
if ((pid = getpid()) < 0) {
fprintf(stderr, "\n\t[starch] - Error: Could not obtain process ID\n\n");
return -1;
}
uname( &uts );
sprintf(uniqTag, "pid%d.%s", pid, uts.nodename);
switch (*argc) {
case 2: {
if (strcmp(*argv[1], "-") != 0) {
if (fileExists(*argv[1]) != 0) { /* standard input */
...
}
return 0;
}
int fileExists(char *fn) {
struct stat buf;
int i = stat (fn, &buf);
if (i == 0)
return 0;
return -1;
}
void printUsage() {
fprintf(stderr, "my usage statement\n\n");
}
My makefile is as follows:
CC = gcc
CFLAGS = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE=1 -DUSE_ZLIB -O3 -Wformat -Wall -pedantic -std=gnu99 -g
BIN = ../bin
all: starch
rm -rf *~
starch: starch.o
mkdir -p $(BIN) && $(CC) ${CFLAGS} starch.o -lbz2 -lz -o ${BIN}/starch
rm -rf *~
clean:
rm -rf *.o *~ ${BIN}/starch
I get the following errors when I run with valgrind:
$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes -v ../bin/starch
...
==2675== 1 errors in context 1 of 2:
==2675== Invalid read of size 8
==2675== at 0x3AB4262243: fwrite (in /lib64/libc-2.5.so)
==2675== Address 0x7fedffd68 is on thread 1's stack
==2675==
==2675==
==2675== 1 errors in context 2 of 2:
==2675== Invalid write of size 8
==2675== at 0x401AA6: parseCommandLineInputs (starch.c:217)
==2675== by 0x7FF0000AF: ???
==2675== by 0x401DFA: main (starch.c:46)
==2675== Address 0x7fedffd68 is on thread 1's stack
The first error is not telling me anything I can use, since I am not using fwrite() anywhere.
The second error is tripped up on the fprintf statement in printUsage().
Line 46 is the following line:
if (parseCommandLineInputs( &argc, &argv ) != 0)
Line 217 is the following line:
fprintf(stderr, "my usage statement\n\n");
What is wrong with my application that explains why these errors appear?
Two things that pop up to me right away:
*argv[1] is NOT the same as (*argv)[1] which is what you probably mean. Array subscripting has precedence over pointer dereferencing. This results in an invalid pointer. As many experienced programmers will tell you: "Don't try to remember the precedence of operators - if in doubt use parentheses, if not just use them anyway".
-O3 in the compiler flags is a big fat NO-NO when debugging. The compiler will mangle your code so much that it can make your life impossible. Variables can disappear completely and functions can go mysteriously away as they get inlined. If your code compiles, links and runs with -O0 (IIRC some code containing inline assembly needs -O1 with some (all?) GCC versions) use it, otherwise use -O1 at most.
There is too much missing so it is not easy to tell what is going on. I suppose that pid is pid_t?
The only thing that I then see is this one:
sprintf(uniqTag, "pid%d.%s", pid, uts.nodename);
pid_t is not necessarily an int so sprintf might be on the wrong track when parsing its arguments and messup your stack. But gcc should have have told you if you compile with -Wall, which I suppose.
Try compiling with a different compiler, clang e.g.

Resources