using ‘-Wcast-qual’ option to check the compilation - c

I am reading an introduction to gcc in which it says:
‘-Wcast-qual’ this option warns about pointers that are cast to remove
a type qualifier, such as const. For example, the following function
discards the const qualifier from its input argument, allowing it to
be overwritten:
void
f (const char * str)
{
char * s = (char *)str;
s[0] = ’\0’; }
The modification of the original contents of str is a violation of its
const property. This option will warn about the improper cast of the
variable str which allows the string to be modified.
I tried to repeat this, expecting a warning, but there's no warning when it is compiled. My code is as follows:
#include <stdio.h>
void f(const char * str);
int main() {
char Str = 'a';
char * myStr;
myStr = & Str;
printf ("result: %c \n", * myStr);
f(myStr);
printf ("result: %c \n", * myStr);
return 0;
}
void
f (const char * str)
{
char * s = (char *)str;
s[0] = '\0';
}
the command is : gcc -Wcast-qual castqual.c
Can anyone explain this inconsistency?

Per the comments, it turns out that the OP is using a mac, where gcc as a command is a wrapper around clang - the llvm based compiler.
The version of clang that's being used accepts the option but does nothing with it. Support for the warning is being added and should appear in the XCode 7/clang 7 timeframe; however the question was about gcc and not about clang.
In this case, you need to install a proper copy of gcc using, either manually or using a package manager such as homebrew or macports. Once you've installed gcc, it becomes available as, for example, gcc-4.8, gcc-5, etc (depends on the package manager). When you want to compile code with actual gcc, you use: gcc-4.8 -Wcast-qual testcode.c. If you're using autoconf tools you can use export CC=gcc-4.8; export CXX=g++-4.8, etc. and then that compiler will be picked up by the package.
Verifying that you're calling gcc, rather than clang requires checking the output from gcc --version. On a clang wrapper you see things like:
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix
whereas on an actual gcc instance you see:
$ gcc-5 --version
gcc-5 (Homebrew gcc 5.1.0) 5.1.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
imho aside: you can make a symlink to the specific gcc-4.8 called gcc, and get it to invoke directly like that but it can break other things.

Related

[msys2][gcc] Wrong output of wprintf() compiling with MSys2's gcc 10.2

I need to get this stripped-down C program working on Windows 7 using MSys2's gcc toolchain:
#include <stdio.h>
void wmain(int argc, wchar_t *argv[])
{
for (int i = 1; i < argc; i++)
wprintf(L"%s\n", argv[i]);
}
The code compiles with
gcc -Wall -municode -O2 -march=x86-64 -m64 test.c
but gives me the following output
>> ./a.exe kk лл
k (!)
:?:?
I have the following questions:
What am I doing wrong?
How would I downgrade the compiler to
version, say, 9.x, or 10.1? (I'm under the impression that the very
same program compiled about one year ago used to work correctly)
Edit [1]: Meanwhile I managed to set up a new MSys2 environment using gcc 9.3. The "error" persists, so it's not the compiler.
Edit [2]: "Some programmer dude" (cmp. below) described the "immediate" solution (THX!).
Even for the wide-character wprintf the format %s is for narrow character strings.
You need to use %ls to print wide-character strings:
wprintf(L"%ls\n", argv[i]);
However this might still not be enough, as the actual encoding of the input (including arguments) might not be what's expected. You need to take into account the encoding used by the terminal the program is running in.

How do I work around the "unknown conversion type character `z' in format" compiler-specific warning?

I'm working on code that is cross-compiled to several target architectures.
I looked at the handful of hits from searching Stack Overflow for "printf size_t unknown conversion type character" warning, however those posts all seem to be related to minGW, so those answers, essentially ifdefing against _WIN32, do not apply to my instance of essentially the same problem, i.e. printf not recognizing "%zu" as the format-specifier for size_t, but with a mips cross compiler.
Is there an existing compiler flag (for the noted cross-compiler) that enables libc to recognize "%zu" as the format-specifier for size_t?
$ cat ./main.c
// main.c
#include <stdio.h>
int main( int argc, char* argv[] )
{
size_t i = 42;
printf( "%zu\n", i );
return 0;
}
$ /path/to/mips_fp_le-gcc --version
2.95.3
$
$ file /path/to/libc.so.6
/path/to/libc.so.6: ELF 32-bit LSB pie executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked, interpreter /lib/ld.so.1, for GNU/Linux 2.2.15, not stripped, too many notes (256)
$
$ /path/to/mips_fp_le-gcc -mips2 -O2 -EL -DEL -pipe -Wall -Wa,-non_shared -DCPU=SPARC -DLINUX -D_REENTRANT -DPROCESS_AUID -DTAGGING -fPIC -I. -I../../../root/include -I../include -I../../../common/include -I../../..
/root/include -DDISABLE_CSL_BITE -DDISABLE_DNS_LOOKUP -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_C
SL_DUPLICATES -DOS=UNIX -DLINUX -DPOSIX_THREADS -D__USE_GNU -D_FORTIFY_SOURCE=2 -DHANDLE_CSL_DUPLICATES -o ./main.o -c main.c
main.c: In function `main':
main.c:6: warning: unknown conversion type character `z' in format
main.c:6: warning: too many arguments for format
If the direct answer to the bolded question is "no", what are other possible solutions? Possibilities that come to mind are...
register_printf_function()
Wrap the format-specifier in a target-specific macro (similar to this minGW-specific post)
...any other ideas? I'd have a strong preference for solutions not involving target-specific preprocessor code, for which reason the above two are not ideal.
I think (but am not sure) that the cross-compiler version is old; are newer versions of the noted toolchain known/guaranteed to have a libc that recognize "%zu" as the format-specifier to size_t?
Update: This cross-compiler seems to not recognize -std=c99; adding it to the compiler flags generates the error "cc1: unknown C standard 'c99'"
I work with a big codebase that's compiled under several different compilers, some of which are old and don't understand %z, so we just do things like
printf("size = %d", (int)size);
That's the easy way for small sizes, of course. If the size might be large, other alternatives are
printf("size = %u", (unsigned)size);
or
printf("size = %lu", (unsigned long)size);
(and there are other obvious possibilities as well).
Your gcc does not support z as a length modifier. It's nothing to do with MIPS, which makes no difference at all, but rather that version 2.95.3 lacks support.
Support for a Z length modifier was added on Feb 9th 1998, commit by Andreas Schwab "c-common.c (format_char_info): Add new field zlen.". There was a gcc extension of Z as a conversion type specifier (rather than length modifier) for size_t before that. This code is in gcc 2.95.3, so it should recognize Z, but not z.
Support for z was added on July 17 2000 by Joseph Myers, "c-common.c (scan_char_table): Allow "z" length modifiers on diouxXn formats". Despite predating gcc 2.95.3 in time, this was in a gcc 3 branch and wasn't released until until gcc 3.0. So your ancient compiler simply hasn't got it.
So you could change your code to use Z, which is still supported. You could also define a macro based on compiler version:
#if __GNUC__ < 3
#define PZ "Z"
#else
#define PZ "z"
#endif
Then use this as in printf("The size is %"PZ"u\n", sizeof(int)); You'll still have to modify your code. But it wouldn't be any different in the end, as the format string, after the preprocessor, would still be %zu on newer compilers and %Zu on old ones. The idea of casting the size_t arguments to something else will actually change the result of the code, as they will be cast to larger/smaller types in some cases, depending on what size_t is and what you cast to.
Alternatively, if you can build your toolchain, you could patch gcc to know about z. I think a one line change in the case statement that uses zlen in "c-common.c" would do it.
register_printf_function() is part of glibc, which is where the printf() code lives. It would allow you to extend printf with new formats at run time. There's nothing you could do at compile time with it that will change the compiler. And I don't believe gcc will be able to know that a new format has been added when it does printf type checking when register_printf_function() is used.

Why does GCC 9.1.0 sometimes complain about this use of strncpy()?

This is a 40-line MCVE (Minimal, Complete, Verifiable Example) — or something close to minimal — cut down from a 1675 line source file that originally included 32 headers (and most of those included multiple other headers — compiling it with gcc -H lists 464 headers from the project and the system, many of them several times). That file is working code that previously compiled without warnings (GCC 8.3.0), but not with GCC 9.1.0. All structure, function, type, variable names have been changed.
pf31.c
#include <string.h>
enum { SERVERNAME_LEN = 128 };
typedef struct ServerQueue
{
char server_name[SERVERNAME_LEN + 1];
struct ServerQueue *next;
} ServerQueue;
extern int function_under_test(char *servername);
#ifdef SUPPRESS_BUG
extern int function_using_name(char *name);
#endif /* SUPPRESS_BUG */
extern int GetServerQueue(const char *servername, ServerQueue *queue);
int
function_under_test(char *servername)
{
ServerQueue queue;
char name[SERVERNAME_LEN + 1];
if (GetServerQueue(servername, &queue) != 0)
return -1;
char *name_in_queue = queue.server_name;
if (name_in_queue)
strncpy(name, name_in_queue, SERVERNAME_LEN);
else
strncpy(name, servername, SERVERNAME_LEN);
name[SERVERNAME_LEN] = '\0';
#ifdef SUPPRESS_BUG
return function_using_name(name);
#else
return 0;
#endif /* SUPPRESS_BUG */
}
Compilation
When compiled using GCC 9.1.0 (on a Mac running macOS 10.14.5 Mojave, or on a Linux VM running RedHat 5.x — don't ask!), with the option -DSUPPRESS_BUG I get no error, but with the option -USUPPRESS_BUG, I get an error:
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -DSUPPRESS_BUG -c pf31.c
$ gcc -std=c11 -O3 -g -Wall -Wextra -Werror -USUPPRESS_BUG -c pf31.c
In file included from /usr/include/string.h:417,
from pf31.c:1:
pf31.c: In function ‘function_under_test’:
pf31.c:30:9: error: ‘__builtin_strncpy’ output may be truncated copying 128 bytes from a string of length 128 [-Werror=stringop-truncation]
30 | strncpy(name, name_in_queue, SERVERNAME_LEN);
| ^~~~~~~
cc1: all warnings being treated as errors
$
When I compile using GCC 8.3.0, I get no errors reported.
Question
Two sides of one question:
Why does GCC 9.1.0 complain about the use of strncpy() when the code is compiled with -USUPPRESS_BUG?
Why doesn't it complain when the code is compiled with -DSUPPRESS_BUG?
Corollary: is there a way to work around this unwanted warning that works with older GCC versions as well as 9.1.0. I've not yet found one. There's also a strong element of "I don't think it should be necessary, because this is using strncpy() to limit the amount of data copied, which is what it is designed for".
Another variant
I have another non-erroring variant, changing the signature of the function_under_test() — here's a set of diffs:
11c11
< extern int function_under_test(char *servername);
---
> extern int function_under_test(char *servername, ServerQueue *queue);
20c20
< function_under_test(char *servername)
---
> function_under_test(char *servername, ServerQueue *queue)
22d21
< ServerQueue queue;
25c24
< if (GetServerQueue(servername, &queue) != 0)
---
> if (GetServerQueue(servername, queue) != 0)
27c26
< char *name_in_queue = queue.server_name;
---
> char *name_in_queue = queue->server_name;
This compiles cleanly regardless of whether SUPPRESS_BUG is defined or not.
As you can guess from the SUPPRESS_BUG terminology, I'm tending towards the view that this is bug in GCC, but I'm kinda cautious about claiming it is one just yet.
More about the the original code: the function itself was 540 lines long; the strncpy() block occurs about 170 lines into the function; the variable corresponding to name was used further down the function in a number of function call, some of which take name as an argument and supply a return value for the function. This corresponds more to the -DSUPPRESS_BUG code, except that in the 'real code', the bug is not suppressed.
This is a GCC bug tracked as PR88780. According to Martin's comment, this warning did not exist prior to GCC 8.
GCC is shipped with this known bug, as it is not deemed release-critical.
To be honest, I am not 100% sure it is the bug. The point is, there are known false-positives. If you feel like helping the GCC project, you can find the most appropriate bug among strncpy / Wstringop-truncation bugs and post your example there. It would be more helpful if you minimized it further (say, with creduce); minimizing the compile string is also appreciated (that would be rather trivial, I guess).
Several compilation warnings related to strncpy were found in GCC 9.0 and reported here and here.
One of them is the error mentioned in the question which seems to occur in the file string_fortified.h:
/usr/include/bits/string_fortified.h:106:10: warning: ‘__builtin_strncpy’ output may be truncated copying 16 bytes from a string of length 16 [-Wstringop-truncation]
106 | return __builtin___strncpy_chk (__dest, __src, __len, __bos (__dest));
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The response to this was given on April 15, 2019 was:
Thank you for the report, however as GCC 9 still under development. We do not see the above errors in the current stable GCC 7.4 or GCC 8.3. We appreciate the advanced notice, and will accept PRs to fix issues against GCC 9, but for now our target compiler is gcc stable.
So I believe the errors are probably a result of versions 9 and 9.1 being not stable versions. Hopefully they will be eliminated when these versions become stable.

Why gettimg error: undefined reference to `sqrt' when passing a variable, but it compiled successfully when passing constant as an argument [duplicate]

I created a small program, as follows:
#include <math.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
double tmp;
double xx;
for(i = 1; i <= 30; i++) {
xx = (double) i + 0.01;
tmp = sqrt(xx);
printf("the square root of %0.4f is %0.4f\n", xx,tmp);
sleep(1);
xx = 0;
}
return 0;
}
When I try to compile this with the following command, I get a compiler error.
gcc -Wall calc.c -o calc
returns:
/tmp/ccavWTUB.o: In function `main':
calc.c:(.text+0x4f): undefined reference to `sqrt'
collect2: ld returned 1 exit status
If I replace the variable in the call to sqrt(xx) with a constant like sqrt(10.2), it compiles just fine. Or, if I explicitly link like the following:
gcc -Wall -lm calc.c -o calc
It also works just fine. Can anyone tell me what's causing this? I've been a C programmer for a long time (and I've written similar small programs using math.h) and I have never seen anything like this.
My version of gcc follows:
$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
If you look at the output of the compiler in the case where you used sqrt(10.2), I'll bet you see that a call to sqrt() isn't actually made.
This happens because GCC recognizes several functions that it can treat specially. This gives it the ability to do certain optimizations, in this case Constant folding. Such special functions are called Built-ins.
In the case where it must link to the math library (because you're calling it with a variable), you need to link it explicitly. Some operating systems/compilers do it for you, which is why you might not have noticed in the past.

sqrt from math.h causes linker error "undefined reference to sqrt" only when the argument is not a constant

I created a small program, as follows:
#include <math.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int i;
double tmp;
double xx;
for(i = 1; i <= 30; i++) {
xx = (double) i + 0.01;
tmp = sqrt(xx);
printf("the square root of %0.4f is %0.4f\n", xx,tmp);
sleep(1);
xx = 0;
}
return 0;
}
When I try to compile this with the following command, I get a compiler error.
gcc -Wall calc.c -o calc
returns:
/tmp/ccavWTUB.o: In function `main':
calc.c:(.text+0x4f): undefined reference to `sqrt'
collect2: ld returned 1 exit status
If I replace the variable in the call to sqrt(xx) with a constant like sqrt(10.2), it compiles just fine. Or, if I explicitly link like the following:
gcc -Wall -lm calc.c -o calc
It also works just fine. Can anyone tell me what's causing this? I've been a C programmer for a long time (and I've written similar small programs using math.h) and I have never seen anything like this.
My version of gcc follows:
$ gcc --version
gcc (Ubuntu 4.3.3-5ubuntu4) 4.3.3
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$
If you look at the output of the compiler in the case where you used sqrt(10.2), I'll bet you see that a call to sqrt() isn't actually made.
This happens because GCC recognizes several functions that it can treat specially. This gives it the ability to do certain optimizations, in this case Constant folding. Such special functions are called Built-ins.
In the case where it must link to the math library (because you're calling it with a variable), you need to link it explicitly. Some operating systems/compilers do it for you, which is why you might not have noticed in the past.

Resources