Been working on my own language for some time now and I've been implementing implicit and explicit casts. Went back to check what happens when invoking them. Everything went well, until I tried to invoke a cast from a double. Passing doubles to functions for some reason results in clang giving me an error when linking the obj file to the cpp file that invokes it, namely:"clang.exe: error: linker command failed with exit code 1143 (use -v to see invocation)program.obj : fatal error LNK1143: invalid or corrupt file: no symbol for COMDAT section 0x5"
I've then noticed this also happens with floats, but does not occur with integers and the likes. I've written a short function (takes a double by value and returns it) to check whether the problem was related to parameters of types float/double. The error only occurs when invoking the function, when defining the function but not invoking it, everything functioned properly. I've also tried to simply store a double literal in memory (alloca) and that worked as well, so the problem has to be with actually passing the argument to the function.
Simple LLVM IR for a function that takes a double by value and returns it, then being invoked from main (main is names _mainCRTStartup as to not confuse it with the symbol for the main function from the cpp file that then invokes it (extern "C"))
Thanks for any help in advance! :D
Related
First of all, I have read this post Why do you need an explicit `-lm` compiler option & this gcc: why is the -lm flag needed to link the math library?. I wanna know why It doesn't happen in case of constants (when I say constants, I mean random floats/doubles)? If you're confused, call it floating-point literals.
Why do we have to use -lm to tell the linker to use math.h functions only when using variables as parameters but not constants? If I use sqrt(N)(N is some number), it compiles fine without any errors but when I pass some variable, let's say sqrt(var), it doesn't. It says:
/usr/bin/ld: /tmp/cc5P9o72.o: in function `main':
sq.c:(.text+0x1b): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status
It should behave the same all the time (I think so, but I am wrong, of-course) as I am using the same function from the same library. Either its variable or constant. I first thought its some kind of compiler optimization (if it's the same value every time, why not calculate it while compiling by some other way, i.e not using the library, as it's not working) but it's doesn't work even if I pass some variable that has a fixed value from beginning to the end. So, I was wrong there. What is actually happening here?
Following is the snippet I tried:
#include <stdio.h>
#include <math.h>
int main () {
float a=9;
printf("%f",sqrt(a));
return 0;
}
It is very simple. When you pass the constants many compilers will evaluate it (in such a trivial example when the result is not float inaccuracies and implementation differences prone) compile time without calling the math.h functions.
Even if you do not pass the constants values and compile it with no math error checks and fast math, the compiler will generate the direct float machine code instructions without calling the library ones
Before asking check the generated code for example using the godbolt.org, and usually it will answer all of your questions
The following is my demo.c file:
main;
On compiling this gcc gives a warning:
demo.c:1:1: warning: data definition has no type or storage class
[enabled by default]
Running ./a.out gives a Segmentation Fault:
Segmentation fault (core dumped)
Is it because, (1) main is not defined anywhere and we are trying to execute it and (2) we are using an imperative statement outside any function, so it can't execute.
In either case, I still don't understand why it should throw a segfault.
Update: It might look similar to Is ‘int main;’ a valid C/C++ program?, but this is different, as not using any identifier, compiles the code.
Your code is formally illegal in standard C (it is generally "non-compilable"). The diagnostic message you received was intended to tell you exactly that.
However, your compiler apparently accepted it and interpreted it is some implementation-specific way. Apparently it interpreted that main as a definition for an int variable with external linkage (legacy K&R C-specific behavior). It created an object file that exports a single external symbol main (likely mangled in some implementation-specific way). Later linker registered that main as your program's entry point.
When you attempt to run your executable, loader passes control to the location of that main variable, mistakenly believing that this is program's entry point. The program crashes, since there's no valid executable code at that location. Or, more likely, it is data execution prevention that causes the program to crash.
I'm working with a large C-only project, and I keep getting bitten by the following problem:
Lets say I have a function
void MyFunction(int parameter)
{
printf("parameter: %d\n", parameter);
}
Which normally gets called
int aVariable = 5;
MyFunction(aVariable);
However, apparently due to the C standard specifications, this does not cause a compilation error:
int aVariable = 5;
MyFunction(&aVariable); // No error signaled, but causes all sorts of mayhem
How can I catch this kind of error, specifically in Visual Studio? Is there any setting I can turn on to make it stricter?
Any strategy you might recommend (besides "don't make typos")?
Edit:
I might add that due to the (crappy) nature of the project, the sample code already generates tons of warnings; I am not sure I can remove all of them in the time I have. Generating more warnings might not be the best option -- however being able to discern about these specific warnings (as one answer suggests) might be the solution to this particular problem.
If the function MyFunction is declared with prototype before the point of the call, then
MyFunction(&aVariable);
is a genuine full-blown constraint violation in C, i.e. it is what we usually call "an error". That's what the language specification says. In other words, your belief that this is somehow allowed "due to the C standard specifications" is incorrect: this is explicitly disallowed by C standard.
Any C compiler will issue at least a warning for such code, which you should also pay attention to. If your C compiler does not report this violation as an error, it can usually be changed through compiler setup.
In case of Visual Studio compiler, one approach is to watch the warning number issued in such cases and ask the compiler to convert such warnings into errors. This can be done through either #pragma warning or through project settings.
Insert a function declaration of the form
void MyFunction(int parameter);
before attempting to call it. If you don't do that, when calling MyFunction() a C compiler is required to assume MyFunction() accepts a variable argument list (arbitrary number and types of arguments) and returns int.
Hence code will compile without error, even if the function is called with incorrect arguments or calling code attempts to use the return value (which should not be done with a void function). The result, if the arguments supplied do not match what the actual function definition expects, is often in the realm of undefined behaviour.
Declaring the function before calling it is good practice, and allows the compiler to detect a problem, and issue errors or warnings as needed. Without the declaration, some compilers do issue warnings, but not all compilers do.
Help!
I am receiving this error when viewing the contents of an inbound function parameters in my Delphi 4 application.
The code calls a function in a dll with 3 parameters (app.handle, pchar, boolean)
The declaring function is in externs.pas and declared as:
function AdjustVoucherDifference(hOwner :HWnd; Receipt_ID :PChar;
bCommit: Boolean): boolean; stdcall;
external 'FBCoupon.dll' name 'AdjustVoucherDifference';
in another source file, the code calls it as:
AdjustVoucherDifference(Application.Handle, PChar(Receipt_ID), true);
When stepping through the code in debug mode, I can see valid values in the source file, but when it breaks on the line in externs.pas, the tooltip for the values (or CTRL+F7) shows that the symbols have been eliminated from the linker and I receive exceptions when the execution is in the dll.
The DLL is developed in CBuilder4 and the particular function is declared as:
BOOL __stdcall __DLLTYPE__ AdjustVoucherDifference(HWND hOwner,
char *receipt_id, bool commit);
Compiler optimization is turned off.
Thanks!!!
Set a breakpoint before the call to the external function (not a breakpoint on the external declaration).
Open the debugger disassembly window. (I forget the exact menu path to get there)
Step through the machine instructions one at a time. You don't need to understand all of them (though it doesn't hurt), but keep a sharp eye out for jump and call instructions.
There will be a bit of chatter as the code sets up the parameters for the call, then a call instruction.
Follow (step into) the call instruction. Since this is an external call, expect to see a jump indirect instruction.
Follow that jump to its destination. You should now be inside the C++ DLL. If you built the DLL in CBuilder with debug info, you should have symbol info and source line info as well.
If your parameter declarations on the Delphi side don't match the expectations on the C++ side, then you should start to see things going awry on the C++ side of the call, which could lead to an access violation exception or a runtime error generated by the C++ dll.
The linker isn't affected by compiler optimizations. The linker will "smartlink out" any routine that it can prove is will never be called in your program. Unfortunately, this means it's not available for the debugger to call into.
My solution to this, when it's happened to me in the past, is generally to put a meaningless call to the routine in question in an initialization section. The smartlinker won't mess with those. Can you do this without causing any errors?
initialization
AdjustVoucherDifference(0, '', true); //DO NOT SMARTLINK THIS OUT!
end;
Note that BOOL and Boolean are different. BOOL is defined in Windows.pas as
type
BOOL = LongBool;
so SizeOf(BOOL) = 4 while SizeOf(Boolean) = 1
Even if it would not help you with your problem, replace Boolean by BOOL (or LongBool) in Delphi declaration to make the declaration correct.
This code compiles, but no surprises, it fails while linking (no main found):
Listing 1:
void main();
Link error: \mingw\lib\libmingw32.a(main.o):main.c:(.text+0x106) undefined reference to _WinMain#16'
But, the code below compiles and links fine, with a warning:
Listing 2:
void (*main)();
warning: 'main' is usually a function
Questions:
In listing 1, linker should have
complained for missing "main". Why
is it looking for _WinMain#16?
The executable generated from
listing 2 simply crashes. What is
the reason?
Thanks for your time.
True, main doesn't need to be a function. This has been exploited in some obfuscated programs that contain binary program code in an array called main.
The return type of main() must be int (not void). If the linker is looking for WinMain, it thinks that you have a GUI application.
In most C compilation systems, there is no type information associated with symbols that are linked. You could declare main as e.g.:
char main[10];
and the linker would be perfectly happy. As you noted, the program would probably crash, uless you cleverly initialized the contents of the array.
Your first example doesn't define main, it just declares it, hence the linker error.
The second example defines main, but incorrectly.
Case 1. is Windows-specific - the compiler probably generates _WinMain symbol when main is properly defined.
Case 2. - you have a pointer, but as static variable it's initialized to zero, thus the crash.
On Windows platforms the program's main unit is WinMain if you don't set the program up as a console app. The "#16" means it is expecting 16 bytes of parameters. So the linker would be quite happy with you as long as you give it a function named WinMain with 16 bytes of parameters.
If you wanted a console app, this is your indication that you messed something up.
You declared a pointer-to-function named main, and the linker warned you that this wouldn't work.
The _WinMain message has to do with how Windows programs work. Below the level of the C runtime, a Windows executable has a WinMain.
Try redefining it as int main(int argc, char *argv[])
What you have is a linker error. The linker expects to find a function with that "signature" - not void with no parameters
See http://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html etc
In listing 1, you are saying "There's a main() defined elsewhere in my code --- I promise!". Which is why it compiles. But you are lying there, which is why the link fails. The reason you get the missing WinMain16 error, is because the standard libraries (for Microsoft compiler) contain a definition for main(), which calls WinMain(). In a Win32 program, you'd define WinMain() and the linker would use the library version of main() to call WinMain().
In Listing 2, you have a symbol called main defined, so both the compiler & the linker are happy, but the startup code will try to call the function that's at location "main", and discover that there's really not a function there, and crash.
1.) An (compiler/platform) dependent function is called before code in main is executed and hence your behavior(_init in case of linux/glibc).
2) The code crash in 2nd case is justified as the system is unable to access the contents of the symbol main as a function which actually is a function pointer pointing to arbitrary location.