secure_getenv function not giving the expected result - c

In my program I am using secure_getenv function to fetch some environment variables. I included stdlib.h in my program. This is the sample call to secure_getenv.
Line 1 : char *myenv;
Line 2 : myenv = __secure_getenv("DATA");
After the above lines execution, myenv points to some junk.
I tried this within gdb after line 2.
p __secure_getenv("DATA")
This prints me the DATA I wanted.
But when I try,
"p myenv",
It prints the below.
$2 = 0×fffffffffffffe13f<Address 0xfffffffffffffe13f out of bounds>"
Can the experts help me to understand what is missing & how to make this work.
Edited to add:
How the myenv is actually used?
In somepoint in time my code tries to call the below.
strlen(myenv);
On strlen function call, my code terminates with sig11(SIGSEGV)

Can the experts help me to understand what is missing & how to make this work.
The most likely cause is that you don't have a prototype for __secure_getenv, which means that the compiler assumes that this function returns an int. That int is then cast to char*, which sign-extends it to produce "garbage" pointer 0xfffffffffffffe13f.
You should compile your source with -Wall -Wextra -- the compiler will then warn you about the bug.
You should #include <stdlib.h> and use secure_getenv() instead of __secure_getenv() -- the former will have a proper prototype.
You can compare the output from p __secure_getenv("DATA") -- it will print the data you expect, and also the pointer value. If my guess is correct, the pointer value will have different high-order bits, but same low 32-bits as myenv == 0xfffffffffffffe13f

Related

Passing the value of a string array to another function

I'm currently in my 1st year of programming and have solved the problem to some code using string arrays but have no idea why it worked. We are still studying pointers but I wanted to try arrays for a bit.
I wanted to pass the value of a string from the main function, to pass to another function, to compare it with another string. If the two strings are equal, it prints "equal" otherwise, it prints "not equal". Although I've solved the problem , I'm confused by how this works:
char name1[100];
scanf("%s",name1);
getname(name1[0]);
return 0;
}
void getname(char name1[0]){
printf("Name1 is %s",name1);
return;
}
If you run it this way, it will not run the function and will return a garbage value. However, if I change
getname(name1[0]);
into
getname(&name1[0]);
it works perfectly fine, why is this?. Secondly, in the "getname" function. since I had to add the ampersand/address to the function call, I was taught that I needed to add an asterisk next to the variable to avoid getting the actual address but to get the actual value. Why is it in
printf("Name1 is %s",name1);
it is able to print the string perfectly fine without needing it to be:
printf("Name1 is %s",*name1);
void getname(char name1[0]) formally says you're going to pass a character array of zero size (side note: zero size arrays are not allowed in standard C but compilers sometimes allow them).
What it really says is you're going to pass a character pointer, a char *. The size is ignored. It's equivalent to the less confusing: void getname(char *name1).
In addition, since you're not going to alter the string inside function you can declare it const char * and be warned if you try to alter it.
#include <stdio.h>
void getname(const char *name1){
printf("Name1 is %s",name1);
return;
}
int main() {
char name[100] = "foo";
getname(name);
}
getname(name1[0]); gives you garbage because instead of passing in the pointer to the start of the string, you're passing in the first character of the string. If the string is "Yarrow Hock" you're trying to pass in Y which is really the number 89. C will then try to read what's at memory address 89 which is probably garbage.
You can see this if you print the memory address of name1 using %p.
void getname(const char *name1){
printf("Name1 points to %p\n",name1);
printf("Name1 is %s\n",name1);
return;
}
You should get a warning like:
incompatible integer to pointer conversion passing 'char' to parameter of
type 'const char *'; take the address with & [-Wint-conversion]
Which leads us to a very important thing: compiler warnings. They are extremely important and by default they are off. Turning them on will save you hours of head scratching. There are a bewildering array of possible warnings and they're slightly different from compiler to compiler. Here's what I use with clang.
-Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c11 -pedantic
You can read what each of these mean in Diagnostic flags in Clang. And yes, "-Wall" does not mean "all warnings".
A good code editor, I recommend Atom, will also give you warnings as you edit.
getname(&name1[0]); works because it is equivalent to getname(name1 + 0) which is equivalent to getname(name1). name1[0] is the first character of the string. & gets its address, which is the start of the string just like name1 itself. printf then prints characters until it hits a null byte.
You can see this by trying getname(&name1[1]), or more directly with pointer arithmetic as getname(name1 + 1). This will pass in the address of the second character in name1. If name1 = "Yarrow Hock" it will print arrow Hock. This is a valid technique for skipping prefixes without altering the string.

C: convert argv[1] to double

I need to pass a double to my program, but the following does not work:
int main(int argc, char *argv[]) {
double ddd;
ddd=atof(argv[1]);
printf("%f\n", ddd);
return 0;
}
If I run my program as ./myprog 3.14 it still prints 0.000000.
Can somebody please help?
My guess is you forgot to include #include <stdlib.h>. If this is the case, gcc will issue the following warning:
warning: implicit declaration of function 'atof' [-Wimplicit-function-declaration]
And give the exact output you provided: 0.000000.
As remyabel indicated, you probably neglected to #include <stdlib.h>. The reason this matters is that, without having a declaration of atof(), the C standard mandates that the return value is assumed to be int. In this case, it's not int, which means that the actual behavior you observe (getting a return value of 0) is technically unspecified.
To be clear, without the double-returning declaration, the line ddd=atof(argv[1]) is treated as a call to an int-returning function, whose result is then cast to a double. It is likely the case that the calling conventions on the particular system you're on specify that ints and doubles get returned in different registers, so the 0 is likely just to be whatever happened to be in that particular register, while the double return value is languishing, unobserved.
In C you don't require to declare a function before you use it (in contrast with C++), and if that happens (no prototype), compiler makes some assumptions about that function. One of those assumptions is that it returns int. There's no error, atof() works, but it works incorrectly. It typically get whatever value happens to be in the register where int is supposed to be returned (it is 0 in your case, but it can be something else).
P.S. atof() and atoi() hide input errors (which you can always see by adding option -Wall to your gcc compiler call: gcc -Wall test.c), so most people prefer to use strtol() and strtod() instead.

Segmentation fault while accessing the return address from a C function in 64 bit machine

I have code in C (linux(x86_64)) some like this:
typedef struct
{
char k[32];
int v;
}ABC;
ABC states[6] = {0};
ABC* get_abc()
{
return &states[5];
}
while in main():
int main()
{
ABC *p = get_abc();
.
.
.
printf("%d\n", p->v);
}
I am getting segmentation fault at printf statement while accessing p->v. I tried to debug it from gdb and it says "can not access the memory". One important thing here is that when I compile this code, gcc throws me a warning on ABC *p = get_abc(); that I am trying to convert pointer from integer. My question here is that I am returning address of structure from get_abc() then why compiler gives me such warning? why compiler considers it as integer? I think I am getting segmentation fault due to this warning as an integer can not hold memory address in x86_64.
Any help would be appreciated.
Define the get_abc prototype before main function. If function prototype is not available before that function call means, compiler will treat that function by default as passing int arguments and returning int. Here get_abc actually returning 8 byte address, but that value has been suppressed to 4 bytes and it is stored in ABC *p variable which leads the crash.
ABC* get_abc();
int main()
{
ABC *p = get_abc();
}
Note : This crash will not occur in 32 bit machine where size of int and size of address is 4 bytes, because suppression will not happen. But that warning will be there.
You haven't shown us all your code, but I can guess with some confidence that the get_abc() and main() functions are defined in separate source files, and that there's no visible declaration of get_abc() visible from the call in main().
You should create a header file that contains a declaration of get_abc():
ABC *get_abc();
and #include that header both in the file that defines get_abc() and in the one that defines main(). (You'll also need header guards.) You'll need to move the definition of the type ABC to that header.
Or, as a quick-and-dirty workaround, you can add an explicit declaration before your definition of main() -- but that's a rather brittle solution, since it depends on you to get the declaration exactly right.
In the absence of a visible declaration, and undeclared function is assumed to return int. The compiler sees your call to get_abc(), generates code to call it as if it returned an int, and implicitly converts that int value to a pointer. Hilarity ensues.
Note: There actually is no implicit conversion from int to pointer types, apart from the special case of a null pointer constant, but many compilers implement such an implicit conversion for historical reasons. Also, the "implicit int" rule was dropped in the 1999 version of the standard, but again, many compilers still implement it for historical reasons. Your compiler should have options to enable better warnings. If you're using gcc, try gcc -pedantic -std=c99 -Wall -Wextra.

C programming language, array, pointer

int main()
{
int j=97;
char arr[4]="Abc";
printf(arr,j);
getch();
return 0;
}
this code gives me a stack overflow error why?
But if instead of printf(arr,j) we use printf(arr) then it prints Abc.
please tell me how printf works , means 1st argument is const char* type so how arr is
treated by compiler.
sorry! above code is right it doesn't give any error,I write this by mistake. but below code give stack overflow error.
#include <stdio.h>
int main()
{
int i, a[i];
getch();
return 0;
}
since variable i take any garbage value so that will be the size of the array
so why this code give this error when i use DEV C++ and if I use TURBO C++ 3.0 then
error:constant expression required displayed. if size of array can't be variable then when
we take size of array through user input.no error is displayed. but why in this case.
please tell me how printf works
First of all, pass only non-user supplied or validated strings to the first argument of printf()!
printf() accepts a variable number of arguments after the required const char* argument (because printf() is what's called a variadic function). The first const char* argument is where you pass a format string so that printf() knows how to display the rest of your arguments.
If the arr character array contains user-inputted values, then it may cause a segfault if the string happens to contain those formatting placeholders, so the format string should always be a hard-coded constant (or validated) string. Your code sample is simple enough to see that it's really a constant, but it's still good practice to get used to printf("%s", arr) to display strings instead of passing them directly to the first argument (unless you absolutely have to of course).
That being said, you use the formatting placeholders (those that start with %) to format the output. If you want to display:
Abc 97
Then your call to printf() should be:
printf("%s %d", arr, j);
The %s tells printf() that the second argument should be interpreted as a pointer to a null-terminated string. The %d tells printf() that the third argument should be interpreted as a signed decimal.
this code gives me a stack overflow error why?
See AndreyT's answer.
I see that now the OP changed the description of the behavior to something totally different, so my explanation no longer applies to his code. Nevertheless, the points I made about variadic functions still stand.
This code results in stack invalidation (or something similar) because you failed to declare function printf. printf is a so called variadic function, it takes variable number of arguments. In C language it has [almost] always been mandatory to declare variadic functions before calling them. The practical reason for this requirement is that variadic functions might (and often will) require some special approach for argument passing. It is often called a calling convention. If you forget to declare a variadic function before calling it, a pre-C99 compiler will assume that it is an ordinary non-variadic function and call it as an ordinary function. I.e. it will use a wrong calling convention, which in turn will lead to stack invalidation. This all depends on the implementation: some might even appear to "work" fine, some will crash. But in any case you absolutely have to declare variadic functions before calling them.
In this case you should include <stdio.h> before calling printf. Header file <stdio.h> is a standard header that contains the declaration of printf. You forgot to do it; hence the error (most likely). There's no way to be 100% sure, since it depends on the implementation.
Otherwise, your code is valid. The code is weird, since you are passing j to printf without supplying a format specifier for it, but it is not an error - printf simply ignores extra variadic arguments. Your code should print Abc in any case. Add #include <stdio.h> at the beginning of your code, and it should work fine, assuming it does what you wanted it to do.
Again, this code
#include <stdio.h>
int main()
{
int j=97;
char arr[4]="Abc";
printf(arr,j);
return 0;
}
is a strange, but perfectly valid C program with a perfectly defined output (adding \n at the end of the output would be a good idea though).
In your line int i, a[i]; in the corrected sample of broken code, a is a variable-length array of i elements, but i is uninitialized. Thus your program has undefined behavior.
You see strings in C language are treated as char* and printf function can print a string directly. For printing strings using this function you should use such code:
printf("%s", arr);
%s tells the function that the first variable will be char*.
If you want to print both arr and j you should define the format first:
printf("%s%d", arr, j);
%d tells the function that the second variable will be int
I suspect the printf() issue is a red herring, since with a null-terminated "Abc" will ignore other arguments.
Have you debugged your program? If not can you be sure the fault isn't in getch()?
I cannot duplicate your issue but then I commented out the getch() for simplicity.
BTW, why did you not use fgetc() or getchar()? Are you intending to use curses in a larger program?
===== Added after your edit =====
Okay, not a red herring, just a mistake by the OP.
C++ does allow allocating an array with the size specified by a variable; you've essentially done this with random (garbage) size and overflowed the stack, as you deduced. When you compile with C++ you are typically no longer compiling C and the rules change (depending on the particular compiler).
That said, I don't understand your question - you need to be a lot more clear with "when we take size of array through user input" ...

Why did this code still work?

Some old code that I just came across:
MLIST * new_mlist_link()
{
MLIST *new_link = (MLIST * ) malloc(sizeof(MLIST));
new_link->next = NULL;
new_link->mapi = NULL;
new_link->result = 0;
}
This was being called to build a linked list, however I noticed there is no statement:
return new_link;
Even without the return statement there, the list still got built properly. Why did this happen?
Edit: Platform: Mandriva 2009 64bit Linux 2.6.24.7-server GCC 4.2.3-6mnb1
Edit: Funny... this code also ran successfuly on about 5 different Linux installations, all different versions/flavors, as well as a Mac.
On 32-bit Windows, most of the time, the return value from a function is left in the EAX register. Similar setups are used in other OSes, though of course it's compiler-specific. This particular function presumably stored the new_link variable in that same location, so when you returned without a return, the variable in that location was treated as the return value by the caller.
This is non-portable and very dangerous to actually do, but is also one of the little things that makes programming in C so much fun.
Possible it just used the EAX register which normally stores the return value of the last function that was called. This is not good practice at all! The behavior for this sort of things is undefined.. But it is cool to see work ;-)
It's basically luck; apparently, the compiler happens to stick new_link into the same place it would stick a returned value.
To avoid this problem, use:
-Wreturn-type:
Warn whenever a function is defined with a return-type that defaults to int. Also warn about any return statement with no return-value in a function whose return-type is not void (falling off the end of the function body is considered returning without a value), and about a return statement with an expression in a function whose return-type is void.
-Werror=return-type to turn the above into an error:
Make the specified warning into an error. The specifier for a warning is appended, for example -Werror=switch turns the warnings controlled by -Wswitch into errors. This switch takes a negative form, to be used to negate -Werror for specific warnings, for example -Wno-error=switch makes -Wswitch warnings not be errors, even when -Werror is in effect. You can use the -fdiagnostics-show-option option to have each controllable warning amended with the option which controls it, to determine what to use with this option.
(from GCCs warning options)
This works by coincidence. You shouldn't rely on that.
Most likely is that it'll produce a very hard to find bug. I'm unsure where I read it, but I recall that if you forget to put in a return statement, most compilers will default to return void.
Here's a short example:
#include <iostream>
using namespace std;
int* getVal();
int main()
{
int *v = getVal();
cout << "Value is: " << *v << endl;
return 0;
}
int* getVal()
{
// return nothing here
}
For me, this works as well. However, when I run it, I get a segment fault. So it's really undefined. Just because it compiles, doesn't mean it'll work.
It works because in the 1940's when the C language was created, there was no return keyword. If you look in the "functions" section of the C43 MINSI standard, it has this to say on the subject (amongst other things):
16.4.3b For backwards compatibility the EAX register MUST be used to return
the address of the first chunk of memory allocated by malloc.
</humour>
Probably a coincidence:
The space for the return value of the function is allocated ahead of time. Since that value is uninitialized, it could have pointed to the same space on the heap as the memory allocated for the struct.

Resources