I read that we need superuser permission to access I/O ports from user space. But i am saying different behavior. ioperm is successful under normal user.
#include <stdio.h>
#include <errno.h>
#include <sys/io.h>
int main(int argc, char *argv[])
{
if (!ioperm(0x70, 3, 1)) {
perror("ioperm failed");
}
else {
printf("ioperm on 0x70 success\n");
}
return 0;
}
$ ./prog
ioperm on 0x70 success
Is this the expected behavior
From the manual:
On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
You have this backwards. -1 means failure, but your code incorrectly assumes it means success.
Related
While testing my code, I have found out readline makes errno 2. This is ENOENT which means No such file or directory.
Does anyone know why??
#include <readline/readline.h>
#include <stdio.h>
#include <errno.h>
int main()
{
char *a = readline("shell$");
printf("%d\n", errno);
while (a)
{
printf("%s\n", a);
readline("shell$");
}
}
Do I have to set errno to 2 after readline? or Is it an error?
its in Macos
compiled with this comm -> gcc -lreadline main.c
Since I am using the Mac which is provided from a kind of institution, I don't have super privileges. Maybe could it cause the error? permission thing?
If a function does not return error value (or otherwise indicate there was an error), then, generally speaking, valuenof errno is not set or reset by it.
So probably some operation done by readline had an error, but it was recoverable and readline succeeded and did not touch errno itself.
So, before checking errno, you have to check if the function failed (or otherwise is documented to set errno in some specific way), usually by checking the return value.
I am currently facing issue with the glibc v2.22 where I am not able to get the proper unwind information.
When there is SIGABRT application, it is calling abort function from glibc. It should be using unwind information which is enabled in the build. However, it is scanning the stack (as indicated by the red line below the address in the screenshot) and providing the misleading information as shown in the screenshot attached (using sentry for analyzing the dump).
Here, do_crash is called which does assert(0) which then aborts the main application. While analyzing the dump, the do_crash function calls the _fini which is never in the main application's stack.
I have enabled unwind for the glibc by using CFLAGS += "-funwind-tables". I also tried with the flags such as -rdynamic and -fno-omit-frame-pointer but it was also of no use.
Am I missing something here? How can I get the complete backtrace of the signals, particularly SIGABRT?
Thanks in advance
When there is SIGABRT application, it is calling abort function from glibc
That is not true, this is not happening, unless you explicitly registered it.
I have enabled unwind for the glibc by using CFLAGS += "-funwind-tables"
It tells the compiler to add the information, it doesn't "enable unwind". What exactly happens when compiling with -funwind-tables?
Here, do_crash is called which does assert(0) which then aborts the main application.
This is not related to receiving SIGABRT signal.
Am I missing something here?
I believe you are making wrong assumptions - that something is called on SIGABRT, that SIGABRT is sent on assert, that abort() is called on SIGABRT. Nothing is called on SIGABRT and the program is terminated when receiving SIGABRT by default (see man 7 signal), assert just terminates the program and doesn't raise SIGABRT, and abort() raises the SIGABRT signal, not receives it.
How can I get the complete backtrace of the signals, particularly SIGABRT?
Register a handler that will do that. See How to automatically generate a stacktrace when my program crashes .
#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int sig) {
void *array[10];
size_t size;
size = backtrace(array, 10);
backtrace_symbols_fd(array, size, STDERR_FILENO);
_Exit(1);
}
int main(int argc, char **argv) {
signal(SIGABRT, handler); // install our handler
raise(SIGABRT);
}
If you want to print stacktrace on assert() that's completely different and you would overwrite the glibc handler for assert to do that:
#include <assert.h>
#include <execinfo.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
void print_trace(void) {
void *array[10];
size_t size;
size = backtrace(array, 10);
backtrace_symbols_fd(array, size, STDERR_FILENO);
}
// based on https://code.woboq.org/userspace/glibc/assert/assert.c.html
void __assert_fail(const char *assertion, const char *file, unsigned int line, const char *function) {
extern const char *__progname;
fprintf(stderr, "%s%s%s:%u: %s%sAssertion `%s' failed.\n",
__progname, __progname[0] ? ": " : "",
file, line,
function ? function : "", function ? ": " : "",
assertion);
print_trace();
abort();
}
int main() {
assert(0);
}
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/sctp.h>
#include <stdio.h>
#include <string.h>
int main(int argc,char **argv)
{
struct sockaddr_in remoteAddr;
int clientSock = socket(PF_INET,SOCK_SEQPACKET,IPPROTO_SCTP);
if(clientSock == -1) {
perror("socket");
return 1;
}
memset(&remoteAddr,0,sizeof remoteAddr);
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_len = sizeof remoteAddr;
remoteAddr.sin_port = htons(5555);
remoteAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
sctp_assoc_t assoc_id = 0;
if(sctp_connectx(clientSock,(struct sockaddr*)&remoteAddr,1, &assoc_id)!= 0) {
perror("sctp_connectx");
return 1;
}
printf("Connected! Assoc ID %d\n",(int)assoc_id);
return 0;
}
When run, this code fails:
$ clang -Wall sctp_connect.c
$ ./a.out
sctp_connectx: Invalid argument
$ uname -rp
11.0-RELEASE-p9 amd64
But I cannot figure out what's wrong. The sctp_connectx() manpage says it will fail with EINVAL if an address with invalid family or no addresses was provided - but that seems not to be the case from the code.
The sctp_connectx() has several parts where it can fail with EINVAL, but truss shows it gets to the setsockopt() call, so it's the kernel that fails the call:
socket(PF_INET,SOCK_SEQPACKET,132) = 3 (0x3)
mmap(0x0,2097152,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34374418432 (0x800e00000)
setsockopt(0x3,0x84,0x8007,0x800e16000,0x14) ERR#22 'Invalid argument'
I think answer is there in your query. If we follow the truss trace then as you said it fails on setsockopt().
So the error EINVAL is returned by setsockopt(). And as per FreeBSD setsockopt() manual:
[EINVAL]: Installing an accept_filter(9) on a non-listening
socket was attempted.
is the description of the error. So I think you should do below things:
Explore your socket options whether they are correct with respect to you listener socket.
Check for the errors for functions htons() and inet_addr()
And my suggestion is that you should not use inet_addr(), for more details see man pages, as per that:
Use of this function is problematic because -1 is a valid address
(255.255.255.255). Avoid its use in favor of inet_aton(),
inet_pton(3), or getaddrinfo(3), which provide a cleaner way to
indicate error return.
I have such a funny problem I thought I'd share with you.
I cornered it down to the most little program I could :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int cmd_left(char *name)
{
pid_t pid;
int f_d;
if ((pid = fork()) == -1)
{
perror("");
exit(1);
}
f_d = open(name);
printf("%d\n", f_d);
close(f_d);
}
int main(int ac, char **av, char **env)
{
char **dummy_env;
if (ac < 2)
return (0);
dummy_env = malloc(10);
cmd_left(av[1]);
}
Basically, if I remove the malloc, opening works just fine.
You just have to compile and give the program a (valid) file to see the magic.
open(2) takes at least two parameters. Since you are passing it only one argument, you are invoking Undefined Behavior. In this case, open() is just using some garbage as second argument.
You need #include <fcntl.h> to get a declaration for open() in scope, which would then tell you that you are not calling it with enough arguments:
int open(const char *filename, int flags, ...);
(The optional argument - singular - is the permissions for the file (mode_t perms) if you have O_CREAT amongst the options in the flags argument.)
The call to malloc() scribbles over enough stack to remove the zeroes on it initially, which leaves the 'extra arguments' to open() in a state where they are not zero and you run into problems.
Undefined behaviour - which you're invoking - can lead to any weird result.
Make sure you compile with at least 'gcc -Wall' and I recommend 'gcc -Wmissing-prototypes -Wstrict-prototypes -Wall -Wextra'.
The header file for open is missing and open expects at least a second parameter.
If you fix that it should be OK.
This is sample program from "Beginning Linux Programming" book:
#include <stdio.h>
#include <term.h>
#include <curses.h>
#include <stdlib.h>
int main()
{
setupterm("unlisted", fileno(stdout), (int *)0);
printf("Done.\n");
exit(0);
}
Running it, I have this result:
./badterm
'unlisted': unknown terminal type.
According to setupterm function definition, it must return 0: "No matching entry in terminfo database". Instead of this, program terminates. Why?
It looks like you asked it to do so. From man setupterm on my machine:
If errret is null, setupterm prints an error message upon finding an
error and exits. Thus, the simplest call is:
setupterm((char *)0, 1, (int *)0);
which uses all the defaults and sends the output to stdout.
Presumably, if you want to handle any error return yourself, you must supply a non-NULL pointer value for the errret (third) parameter.