My point is to show someone that every argument you sent to a C function, are pushed on the stack. It also happens in Ruby, Python, Lua, JavaScript, etc.
So I have written a Ruby code that generates a C code:
#!/usr/bin/env ruby
str = Array.new(10, &:itself)
a = <<~EOF
#include <stdio.h>
void x(#{str.map { |x| "int n#{x}" }.join(?,)}) {
printf("%d\\n", n#{str.length - 1}) ;
}
int main() { x(#{str.join(?,)}) ; }
EOF
IO.write('p.c', a)
After running this code with the Ruby interpreter, I get a file called p.c, which has this content:
#include <stdio.h>
void x(int n0,int n1,int n2,int n3,int n4,int n5,int n6,int n7,int n8,int n9) {
printf("%d\n", n9) ;
}
int main() { x(0,1,2,3,4,5,6,7,8,9) ; }
Which is good, and does compile and execute just fine.
But if I give the ruby program an array size of 100,000, it should generate a C file that takes n0 to n999999 arguments. That means 100,000 arguments.
A quick google search shows me that C's arguments are stored on the stack.
Passing these arguments should give me a stackerror, but it doesn't. GCC compiles it just fine, I also get output of 99999.
But with Clang, I get:
p.c:4:17: error: use of undeclared identifier 'n99999'
printf("%d\n", n99999) ;
^
p.c:8:195690: error: too many arguments to function call, expected 34464, have 100000
p.c:3:6: note: 'x' declared here
2 errors generated.
How does GCC deal with that many arguments? In most cases, I get stackerror on other programming languages when the stacksize in 10900.
The best way to prove this to your friend is to write an infinite recursive function:
#include <stdio.h>
void recurse(int x) {
static int iterations=0;
printf("Iteration: %d\n", ++iterations);
recurse(x);
}
int main() {
recurse(1);
}
This will always overflow the stack assuming there is a stack (not all architectures use stacks). It will tell you how many stack frames you get to before the stack overflow happens; this will give you an idea of the depth of the stack.
As for why gcc compiles, gcc does not know the target stack size so it cannot check for a stack overflow. It's theoretically possible to have a stack large enough to accommodate 100,000 arguments. That's less than half a megabyte. Not sure why clang behaves differently; it would depend on seeing the generated C code.
If you can share what computer system/architecture you are using, it would be helpful. You cited information that applies to 64-bit Intel systems (e.g. PC/Windows).
Related
I'm writing a basic compiler and the code generated does not work as intended.
I'm using a naive graph coloring algorithm to allocate variables in registers based on their liveness.
The problem is that the generated assembly code seems perfectly fine, but, at some point, it produces undefined behaviour.
If, instead of using registers to store variables, I just use the stack, everything works fine.
I also discovered that I can't use the %edx register around an imull instruction and I wondered if something similar is happening right now with %ebx and %ecx.
I compile the code using gcc -m32 "test.s" runtime.c -o test, where runtime.c is a helper C file containing the print and input functions.
I've also tried to remove parts of the program (every print except the last one) and then the last print will work.
If I call a single print function before the last call it won't work.
The runtime.c file:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int input() {
int num;
char term;
scanf("%d%c", &num, &term);
return num;
}
void print_int_nl(int i) {
printf("%d\n", i);
}
Source file:
a = 10
b = input()
c = - 10
d = -input()
print a
print b
print c
print d
Generated assembly code:
https://pastebin.com/ChSRbWgt
After compiling the .s file and running it using the console (./test) it asks for 2 input (as intended).
I give it 1 and 2.
Then the output is:
10
1
-10
1415880
instead of
10
1
-10
-2
You need to observe the calling convention (see e.g. Calling conventions for different C++ compilers and operating systems by Agner Fog).
Namely, there are caller-save and callee-save registers in the convention for your C compiler.
Your generated code needs to preserve the callee-save registers in order to be able to return to its C caller.
Similarly, printf() will preserve the callee-save registers, but it can trash the caller-save registers, meaning that if your generated code calls printf(), it will need to preserve the caller-save registers across the calls to printf() or any other C function.
You need to clear the input buffer after your first input the buffer still contains the newline character i'd recommend this :
int input() {
int num;
char term;
scanf("%d %c", &num, &term);
return num;
}
I'm writing my own test-runner for my current project. One feature (that's probably quite common with test-runners) is that every testcase is executed in a child process, so the test-runner can properly detect and report a crashing testcase.
I want to also test the test-runner itself, therefore one testcase has to force a crash. I know "crashing" is not covered by the C standard and just might happen as a result of undefined behavior. So this question is more about the behavior of real-world implementations.
My first attempt was to just dereference a null-pointer:
int c = *((int *)0);
This worked in a debug build on GNU/Linux and Windows, but failed to crash in a release build because the unused variable c was optimized out, so I added
printf("%d", c); // to prevent optimizing away the crash
and thought I was settled. However, trying my code with clang instead of gcc revealed a surprise during compilation:
[CC] obj/x86_64-pc-linux-gnu/release/src/test/test/test_s.o
src/test/test/test.c:34:13: warning: indirection of non-volatile null pointer
will be deleted, not trap [-Wnull-dereference]
int c = *((int *)0);
^~~~~~~~~~~
src/test/test/test.c:34:13: note: consider using __builtin_trap() or qualifying
pointer with 'volatile'
1 warning generated.
And indeed, the clang-compiled testcase didn't crash.
So, I followed the advice of the warning and now my testcase looks like this:
PT_TESTMETHOD(test_expected_crash)
{
PT_Test_expectCrash();
// crash intentionally
int *volatile nptr = 0;
int c = *nptr;
printf("%d", c); // to prevent optimizing away the crash
}
This solved my immediate problem, the testcase "works" (aka crashes) with both gcc and clang.
I guess because dereferencing the null pointer is undefined behavior, clang is free to compile my first code into something that doesn't crash. The volatile qualifier removes the ability to be sure at compile time that this really will dereference null.
Now my questions are:
Does this final code guarantee the null dereference actually happens at runtime?
Is dereferencing null indeed a fairly portable way for crashing on most platforms?
I wouldn't rely on that method as being robust if I were you.
Can't you use abort(), which is part of the C standard and is guaranteed to cause an abnormal program termination event?
The answer refering to abort() was great, I really didn't think of that and it's indeed a perfectly portable way of forcing an abnormal program termination.
Trying it with my code, I came across msvcrt (Microsoft's C runtime) implements abort() in a special chatty way, it outputs the following to stderr:
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
That's not so nice, at least it unnecessarily clutters the output of a complete test run. So I had a look at __builtin_trap() that's also referenced in clang's warning. It turns out this gives me exactly what I was looking for:
LLVM code generator translates __builtin_trap() to a trap instruction if it is supported by the target ISA. Otherwise, the builtin is translated into a call to abort.
It's also available in gcc starting with version 4.2.4:
This function causes the program to exit abnormally. GCC implements this function by using a target-dependent mechanism (such as intentionally executing an illegal instruction) or by calling abort.
As this does something similar to a real crash, I prefer it over a simple abort(). For the fallback, it's still an option trying to do your own illegal operation like the null pointer dereference, but just add a call to abort() in case the program somehow makes it there without crashing.
So, all in all, the solution looks like this, testing for a minimum GCC version and using the much more handy __has_builtin() macro provided by clang:
#undef HAVE_BUILTIN_TRAP
#ifdef __GNUC__
# define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
# if GCC_VERSION > 40203
# define HAVE_BUILTIN_TRAP
# endif
#else
# ifdef __has_builtin
# if __has_builtin(__builtin_trap)
# define HAVE_BUILTIN_TRAP
# endif
# endif
#endif
#ifdef HAVE_BUILTIN_TRAP
# define crashMe() __builtin_trap()
#else
# include <stdio.h>
# define crashMe() do { \
int *volatile iptr = 0; \
int i = *iptr; \
printf("%d", i); \
abort(); } while (0)
#endif
// [...]
PT_TESTMETHOD(test_expected_crash)
{
PT_Test_expectCrash();
// crash intentionally
crashMe();
}
you can write memory instead of reading it.
*((int *)0) = 0;
No, dereferencing a NULL pointer is not a portable way of crashing a program. It is undefined behavior, which means just that, you have no guarantees what will happen.
As it happen, for the most part under any of the three main OS's used today on desktop computers, that being MacOS, Linux and Windows NT (*) dereferencing a NULL pointer will immediately crash your program.
That said: "The worst possible result of undefined behavior is for it to do what you were expecting."
I purposely put a star beside Windows NT, because under Windows 95/98/ME, I can craft a program that has the following source:
int main()
{
int *pointer = NULL;
int i = *pointer;
return 0;
}
that will run without crashing. Compile it as a TINY mode .COM files under 16 bit DOS, and you'll be just fine.
Ditto running the same source with just about any C compiler under CP/M.
Ditto running that on some embedded systems. I've not tested it on an Arduino, but I would not want to bet either way on the outcome. I do know for certain that were a C compiler available for the 8051 systems I cut my teeth on, that program would run fine on those.
The program below should work. It might cause some collateral damage, though.
#include <string.h>
void crashme( char *str)
{
char *omg;
for(omg=strtok(str, "" ); omg ; omg=strtok(NULL, "") ) {
strcat(omg , "wtf");
}
*omg =0; // always NUL-terminate a NULL string !!!
}
int main(void)
{
char buff[20];
// crashme( "WTF" ); // works!
// crashme( NULL ); // works, too
crashme( buff ); // Maybe a bit too slow ...
return 0;
}
So I am currently learning assembly language (AT&T syntax). We all know that gcc has an option to generate assembly code from C code with -S argument. Now, I would like to look at some code, how it looks in assembly. The problem is, on laboratories we compile it with as+ld, and as for now, we cannot use C libraries. So for example we cannot use printf. We should do it by syscalls (32 bit is enough). And now I have this code in C:
#include <stdio.h>
int main()
{
int a = 5;
int b = 3;
int c = a + b;
printf("%d", c);
return 0;
}
This is simple code, so I know how it will look with syscalls. But if I have some more complicated code, I don't want to mess around and replace every call printf and modify other registers, cuz gcc generated code for printf, and I should have it with syscalls. So can I somehow make gcc generate assembly code with syscalls (for example for I/O (console, files)), not with C libs?
Under Linux there exist the macro family _syscallX to generate a syscall where the X names the number of parameters. It is marked as obsolete, but IMHO still working. E.g., the following code should work (not tested here):
_syscall3(int,syswrite,int,handle,char*,str,int len);
// ---
char str[]="Hello, world!\n";
// file handle 1 is stdout
syswrite(1,str,14);
I am new to C programming and I am currently learning loops. In the below program,
#include<stdio.h>
main()
{
int i;
for(i=1;i++<=5;printf("%d",i));
}
i tried to compile in dev c++ compiler but it is giving error "[Error] ld returned 1 exit status"
You need to include the <stdio.h> header, and also, main needs a return type (int) and a return value. Changing the program to this will make it compile (at least it did using GCC) and run:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
for(i=1;i++<=5;printf("%d",i));
return 0;
}
The quotes you used in the ā%dā are illegal too, use normal quotes: "%d".
Apart from that, doing the printf inside the loop head might be legal, but it's pretty bad style. Usually in a for-loop you would have have initialization;condition;increment(or decrement or w/e) in the head, and do side-effects in the body of the statement.
I would try writing the for loop as:
for(i=1;i < 6;i++) { printf(ā%dā,i); }
I have run this program manually on my notebook and i got Output 23456
Then i run this on Dev c++ and it is giving the same output 23456 without any error and i have just copied and pasted from ur question dun know why its showing error on ur runtime may be u have not saved it as C file
A simple C program which uses gettimeofday() works fine when compiled without any flags ( gcc-4.5.1) but doesn't give output when compiled with the flag -mno-sse.
#include <stdio.h>
#include <stdlib.h>
int main()
{
struct timeval s,e;
float time;
int i;
gettimeofday(&s, NULL);
for( i=0; i< 10000; i++);
gettimeofday(&e, NULL);
time = e.tv_sec - s.tv_sec + e.tv_usec - s.tv_usec;
printf("%f\n", time);
return 0;
}
I have CFLAGS=-march=native -mtune=native
Could someone explain why this happens?
The program returns a correct value normally, but prints "0" when compiled with -mno-sse enabled.
The flag -mno-sse causes floating point arguments to be passed on the stack, whereas the usual x86_64 ABI specifies that they should be passed via SSE registers.
Since printf() in your C library was compiled without -mno-sse, it is expecting floating point arguments to be passed in accordance with the ABI. This is why your code fails. It has nothing to do with gettimeofday().
If you wish to use printf() from your code compiled with -mno-sse and pass it floating point arguments, you will need to recompile your C library with that option and link against that version.
It appears that you are using a loop which does nothing in order to observe a time difference. The problem is, the compiler may optimize this loop away entirely. The issue may not be with the -mno-sse itself, but may be that that allows an optimization that removes the loop, thus giving you the same time each time you run it.
I would recommend trying to put something in that loop which can't be optimized out (such as incrementing a number which you print out at the end). See if you still get the same behavior. If not, I'd recommend looking at the generated assembler gcc -S and see what the code difference is.
The datastructures tv_usec and tv_sec are usually longs.
Redeclaration of the variable "time" as a long integer solved the issue.
The following link addresses the issue.
http://gcc.gnu.org/ml/gcc-patches/2006-10/msg00525.html
Working code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
struct timeval s,e;
long time;
int i;
gettimeofday(&s, NULL);
for( i=0; i< 10000; i++);
gettimeofday(&e, NULL);
time = e.tv_sec - s.tv_sec + e.tv_usec - s.tv_usec;
printf("%ld\n", time);
return 0;
}
Thanks for the prompt replies. Hope this helps.
What do you mean doesn't give output?
0 (zero) is a perfectly reasonable output to expect.
Edit: Try compiling to assembler (gcc -S ...) and see the differences between the normal and the no-sse version.