strcasecmp NULL argument; man strcasecmp - c

I made a small program that sigsegved on strcasecmp, and had no idea why until I made this test case:
strcasecmp(NULL, "TEST");
which, when compiled, got me the following warning:
test.c:9:4: warning: null argument where non-null required (argument 1) [-Wnonnull]
However, man strcasecmp doesn't say anything about NULL arguments, could someone please explain how I could deduce this theoretically from reading documentation, as opposed to empirically writing test cases? Is it a deeper-rooted standard? Or maybe const char * doesn't have the right to be NULL, for some reason I don't know?

Nobody has actually explained why this is the case yet.
It it undefined behaviour. Why?
Each of the following statements applies unless explicitly stated otherwise
in the detailed descriptions that follow: If an argument to a function has an
invalid value (such as a value outside the domain of the function, or a
pointer outside the address space of the program, or a null pointer, or a
pointer to non-modifiable storage when the corresponding parameter is not
const-qualified) or a type (after promotion) not expected by a function with
variable number of arguments, the behavior is undefined.
(C standard, 7.1.4)
Since strcasecmp never mentions NULL, it is outside the domain of the function. So the function is free to do as it pleases. Including crash.
(Note: my source here is this related answer: https://stackoverflow.com/a/12621203/1180785)

I think it's assumed you have a rough idea of the consequences. You will have a similar experience if you try this, which uses a non-NULL argument:
strcasecmp((const char *)1, "A string");

String compare strcasecmp requires 2 parameters, both with non-null strings. Since both are pointers, NULL is also valid. However strcasecmp could have been defined as:
int strcasecmp(const char *s1, const char *s2) __attribute__((nonnull));
This attribute will produce warnings if at least one argument is NULL.

Related

How is sizeof(*NULL) equal to 1 on 32-bit C compiler?

I recently learned that sizeof is not a function and actually evaluates at compile time.
But I still haven't been able to figure out how sizeof(*NULL) is equal to 1.
EDIT: I'm talking about gcc here specifically.
It depends on the compiler and standard library. With GCC and glibc, NULL is defined as (void*)0 and GCC has an extension that allows pointer arithmetic on void pointers using sizeof(void) == 1. Without this extension, the compiler would produce an error.
A standard library could also define NULL as 0. In this case sizeof(*NULL) would also be illegal.
Standard makes no guarantee as to the value returned by sizeof(*NULL), which is enough to not use this construct in practice.
Your code uses implementation-defined behavior.
7.173 The macros are
NULL
which expands to an implementation-defined null pointer constant
This means that the standard does not guarantee that your code is going to compile, let alone producing a certain value.
On systems defining macro NULL as ((void*)0) your code will trigger a warning that should be treated as an error:
prog.c:4:28: error: invalid application of ‘sizeof’ to a void type [-Werror=pointer-arith]
Demo.
Since NULL has type void *, that would mean *NULL has type void. Taking the size of void is not allowed by the C standard, although some compilers do as an extension.
In GCC, it treats the size of void as 1 to allow pointer arithmetic on void *.
On "old time" NULL was defined as:
#define NULL ((char *)0)
so with *NULL you get a char, which has size of 1. (You can still see such definition hidden in headers, as fall back case, now, starting with C90, the char is substituted with void).
I do not think it is a valid code (indirection of NULL, also just to take the size).
On some compilers null is 0l or just 0, which will give an error in your case.

How to check if command line arguments are lower case/ alphabetic and the sort?

I am really new to C programming (have previously done python and this is quite a difficult transition). I have been given a task to check the command line arguments and those which are not lower case alphabetic or numeric should be printed out with a given statement.
I have tried using a for loop and tried checking islower for argv[i] but that just crashes my program. The compiler gives this warning:
passing argument 1 of 'islower' makes integer from pointer without a cast
Can someone please give a general idea without actually typing out the code? Please do no type the code as I really want to do this myself (and also might get into trouble for plagiarism).
islower() checks the case of a single character, whereas argv is a char ** variable, meaning that argv[i] is a string (a char *), not a character. Thus, to check whether a particular argument is lower-case, you need to iterate over the characters in it to check each one.
Which is also the meaning of the warning message you mention. Since the argument to islower() is an int (a single character), and you pass it a pointer (that is, argv[i], which is a char *), the compiler implicitly casts that pointer to the int that islower() requires, which is seldom intended behavior.

Enforcing ending variadic function parameters with NULL

Is it possible to make declaration of variadic function so that it doesn't end with "..."?
Today I learned more about exec from unistd.h but through the day I've seen three (two actually) different declaration of execl:
1) int execl ( const char * path, const char * arg0, ..., (char*)NULL ); was shown to us in school and I imagined I would have to end the function call with a NULL value
2) int execl(const char *path, const char *arg, ... /* (char *) NULL */); is what I've found in the exec(3) man page. That would probably mean I still have to end it with a NULL value, but it is not enforced.
3) int execl(const char *path, const char *arg, ...); is what I found here. This one would probably normally put me to rest with the first one being a simplification for students, the second was a varning and this is the real thing (even though I would probably have normally higher regard for both options one and two.)
But then I found on the same site this declaration:
int execle(const char *path, const char *arg, ..., char * const envp[]);
Same question applies, I was unable to create variadic function not ending in ... with gcc telling me that it's expecting ')' before ',' token pointing to the comma after the three dots.
So finally, is it possible to make variadic functions ending with a NULL characters (execl) and if not, is it possible to make it end with predefined variable (execle)?
I tried to compile with gcc 6.3.1, I also tried --std=c11.
Is it possible to make declaration of variadic function so that it doesn't end with "..."?
Is it possible is a slippery question, but consider these facts:
the standard says that "If a function that accepts a variable number of arguments is defined without a parameter type list that ends with the ellipsis notation, the behavior is undefined" (C2011, 6.9.1/8)
Perhaps that answers the question already, but if you choose to mince words and focus on function declarations that are not definitions, then
a function definition is also a declaration
the C language standard requires all declarations of the same function to be "compatible" (else program behavior is undefined) (C2011 6.7/4)
two function declarations with mismatched parameter lists are not compatible (C2011, 6.2.7/3)
Thus, if you declare a variadic function that in fact is also defined, and that function's parameter list does not end with ..., then the program's behavior is undefined.
The documentation you've been reading for execle() and execl() is written to express and discuss those functions' expectations, but to the extent that it seems to present variadic function declarations in which the last element of the parameter list is not ..., those are not actually valid C function declarations.
So finally, is it possible to make variadic functions ending with a NULL characters (execl) and if not, is it possible to make it end with predefined variable (execle)?
It is not possible to describe such calling conventions via conforming C declarations. Variadic functions can have such expectations, and can enforce them at runtime, but they can be enforced at compile time only by a compiler that relies on special knowledge of the functions involved, or on C language extensions that allow such constraints to be described.
The declaration of a variadic function can only specify the required arguments, and the compiler can enforce their types. The variable-length part never has any type checking done. And the variable-length part is always at the end. The declaration for execle() is not meant as an actual C declaration, but just to describe to the programmer how he should construct the arguments.
It's not possible to enforce that the last argument to execl() is NULL. Variadic functions don't know how many arguments were supplied, they determine it from the values of the arguments. printf() assumes that it has enough arguments to fill in all the operators in the format string, and execl() iterates through the arguments until it finds NULL (execle() is similar, but it reads one additional argument to get envp). If you don't end with NULL, it will just keep going, reading garbage and causing undefined behavior.
The declaration you see is the one in the man pages of execl. The declaration for execle in glib is the following: int execle (const char *path, const char *arg, ...). The implementation assumes the last argument is a char**, and uses it for envp. I don't think you can enforce such a rule in C.

Why do I get a warning about printf() with %s taking type void * as parameter?

I'm on programming project 4 from chapter 19 of C programming, A Modern Approach. My code works but I get this warning trying to pass a function returning a void * parameter to printf with conversion specifier %s.
format %s expects argument of type char *, but argument 2 has type void * [-Wformat=]
I can easily get rid of the warning by casting the return type of the function to char *, like
printf("%s\n", (char *) function(param));
but I just want to know why this necessary since type void * is casted to another pointer type automatically.
Compiler is very right to complain in this case.
As per your logic itself, the function returning void * could return a structure pointer casted to void *, but then, %s won't be able to print that, isn't it?
So, if you know what you're doing, you can cast the result, for this case.
Also, as others pointed out, maybe it's worthy to mention that, this warning has nothing to do with the standard specification, as in the standards, there is no restriction of the type of the arguments. (Borrowing Mr. #WhozCraig's words) This warning is basically due to an additional layer of type-checking entirely performed by compiler on it's own, enabled by -Wformat flag in gcc .
As far as the pure language is concerned (not the standard library and its expectations, the actual formal language) you can push anything you want on that argument list (including something utterly incoherent in relating to the requirements of a %s format specifier of some library routine). Of course, unless whatever you pushed ultimately is, in fact, the address of a nullchar terminated sequence of char, printf itself will trapes into undefined behavior at your behest.
The warning you're receiving is based on an additional layer of api-checking within the compiler, not some violation of the language itself. That api checking is matching format specs with types of presented arguments for frequently-used standard library apis such as printf, scanf, etc. Could the author of that warning-check been a little more forgiving and ignore void* arguments for specs expecting pointer-types? Certainly, but the point of the check-feature would dwindle pretty rapidly were that the case. Consider this:
int a = 0;
void *b = &a;
printf("%s\n", b);
If that api-check feature is going to be worth any salt at all it had better bark about that mismatched type, because as far as the language itself is concerned, there is nothing wrong with this code. And that has nothing to do with what evil I just requested it do. As far as the language is concerned, printf is simply this:
int printf(char *format ...);
And the call I setup certainly fulfills that (bad for me, and thankfully, the api-checks of my modern compiler will let me know soon enough there may be a problem).
A pointer is a variable which points to a single memory location.
The number of bytes pointed by the pointer depends on the type of the pointer. So if it is int* then it is interpreted as 4 bytes,if it is a char* it is interpreted as 1 byte.
A void* has no type. So the compiler cant dereference this pointer. So in order for the compiler to understand the memory to be dereferenced we need typecasting here.
The printf function is declared as something like this:
int printf(char *format ...);
Here ... denotes any additional arguments the caller supplied (that is, your string you wanted to print). When printf examines these additional parameters, it uses some low-level code, which has no type safety.
This code cannot determine that the parameter has type void*, and cast it to char* automatically. Instead, if the binary representation of void* and char* is the same, the parameter can be extracted from the ... part without regard to its actual type. If the representation is different, the low-level code will try to print an incorrect value (and probably crash).
Representation of void* and char* is the same for all platforms that I know of, so it's probably safe (if you trust me, that is - please don't!). However, if you compile with gcc -Wall, as some people recommend, all warnings are upgraded to errors, so you should do the casting, as the compiler indicates.

Can memset() be called with a null pointer if the size is 0?

For one reason or another, I want to hand-roll a zeroing version of malloc(). To minimize algorithmic complexity, I want to write:
void * my_calloc(size_t size)
{
return memset(malloc(size), 0, size);
}
Is this well-defined when size == 0? It is fine to call malloc() with a zero size, but that allows it to return a null pointer. Will the subsequent invocation of memset be OK, or is this undefined behaviour and I need to add a conditional if (size)?
I would very much want to avoid redundant conditional checks!
Assume for the moment that malloc() doesn't fail. In reality there'll be a hand-rolled version of malloc() there, too, which will terminate on failure.
Something like this:
void * my_malloc(size_t size)
{
void * const p = malloc(size);
if (p || 0 == size) return p;
terminate();
}
Here is the glibc declaration:
extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
The __nonnull shows that it expects the pointer to be non-null.
Here's what the C99 standard says about this:
7.1.4 "Use of library functions"
If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or a type (after promotion) not expected by a function with variable number of arguments, the behavior is undefined.
7.21.1 "String function conventions" (remember that memset() is in string.h)
Where an argument declared as size_t n specifies the length of the array for a function, n can have the value zero on a call to that function. Unless explicitly stated otherwise in the description of a particular function in this subclause, pointer arguments on such a call shall still have valid values, as described in 7.1.4.
7.21.6.1 "The memset function"
The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.
So strictly speaking, since the standard specifies that s must point to an object, passing in a null pointer would be UB. Add the check (the cost compared to the malloc() will be vanishingly small). On the other hand, if you know the malloc() cannot fail (because you have a custom one that terminates), then obviously you don't need to perform the check before calling memset().
Edit Re:
I added this later: Assume that malloc() never fails. The question is only if size can be 0
I see. So you only want things to be secure if the pointer is null and the size is 0.
Referring to the POSIX docs
http://pubs.opengroup.org/onlinepubs/009695399/functions/memset.html
http://pubs.opengroup.org/onlinepubs/7908799/xsh/memset.html
No, it is not specified that it should be safe to call memset with a null pointer (if you called it with zero count or size... that'd be even more 'interesting', but also not specified).
Nothing about it is even mentioned in the 'informative' sections.
Note that the first link mentions
The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of IEEE Std 1003.1-2001 defers to the ISO C standard
Update I can confirm that the ISO C99 standard (n1256.pdf) is equally brief as the POSIX docs and the C++11 spec just refer to the ANSI C standard for memset and friends. N1256 states:
The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.
and says nothing about the situation where s is null (but note that a null pointer does not point to an object).

Resources