Illegal Instruction while using zlib in uCLinux environment - zlib

This may be completely irrelevant or very simple question.
I'm trying to write a very simple application that uses the libz library functions to do compression. It should run in uCLinux environment on a NIOS CPU. My system runs busybox and busybox provides all the regular gzip, gunzip functionalities. But they are built into busybox and as far as I can tell not using the dynamic libz library.
Here is the code:
{
printf("Hello World\n");
printf("Zlib: %s\n", zlibVersion());
gzFile file = gzopen ("/tmp/s2.log.gz", "wb");
if (! file) {
fprintf (stderr, "gzopen failed: %s.\n", strerror (errno));
exit (-1);
}
printf("%d\n", __LINE__);
{
unsigned char buffer[LENGTH] = "Hello world";
int bytes_read = gzwrite (file, buffer, LENGTH - 1);
if (bytes_read < LENGTH - 1) {
int err;
const char * error_string;
error_string = gzerror (file, & err);
if (err) {
fprintf (stderr, "Error: %s.\n", error_string);
exit (-1);
}
}
}
printf("%d\n", __LINE__);
printf("%d\n", gzclose (file));
return 0;
}
It is partially lifted from zlib example. The problem is that on the last line - gzclose - when the compressed buffer actually flushed to the file, I get illegal instruction exception.
Anyone has any idea why it may be happening?
Here is the backtrace from GDB of the failure:
#0 0x2aad9efc in order.3344 () from ./uClinux/uClinux-dist/staging/usr/lib/libz.so.1
#1 0x2aad21c8 in _tr_flush_block () from ./uClinux/uClinux-dist/staging/usr/lib/libz.so.1
#2 0x2aace694 in deflate_slow () from ./uClinux/uClinux-dist/staging/usr/lib/libz.so.1
#3 0x2aacec9c in deflate () from ./uClinux/uClinux-dist/staging/usr/lib/libz.so.1
#4 0x2aacb5d0 in gzclose () from ./uClinux/uClinux-dist/staging/usr/lib/libz.so.1
#5 0x0000193c in main () at main.c:49
Update: I've linked the libz.a statically, but the same error occurred.

Found the cause of the problem.
The original zlib uses -O3 optimization flag. It is possible that either my NIOSII CPU or the compiler is not up to the task to create properly running code. Once I've relaxed the optimization flag the error went away.

Related

Stack Smashing Issue With Pipes, greps, wc in C

EDIT: ** QUESTION HAS BEEN ANSWERED: see comments by PaulMckenzie and Rishikesh Raje
The intention of this function is to call grep on parameter file with parameter pattern using pipes, but I am having an issue with stack smashing in my program. It runs through and works straight through to the end of the function, but then complains of stack smashing.
Here's my code:
void count_pattern(char *file, char *pattern) {
int bytes_read;
int nbytes = 20000;
char *read_string;
char grep_str[] = "";
FILE *grep_pipe;
FILE *wc_pipe;
strcat(grep_str, "grep ");
strcat(grep_str, pattern);
strcat(grep_str, " ");
strcat(grep_str, file);
strcat(grep_str, "\0");
grep_pipe = popen (grep_str, "r");
wc_pipe = popen ("wc -l", "w");
/* Pipe Error Checking*/
if ((!grep_pipe) || (!wc_pipe))
{
fprintf (stderr,"One or both pipes failed.\n");
}
/* Read from grep_pipe until EOF? */
read_string = (char *) malloc (nbytes + 1);
bytes_read = getdelim (&read_string, &nbytes, -1, grep_pipe);
/* Close grep_pipe */
if (pclose (grep_pipe) != 0)
{
fprintf (stderr, "Could not run 'grep'.\n");
}
/* Send output of 'grep' to 'wc' */
fprintf (wc_pipe, "%s", read_string);
/* Close wc_pipe */
if (pclose (wc_pipe) != 0)
{
fprintf (stderr, "Could not run 'wc'.\n");
}
printf("%s\n\n",grep_str); /* migrating bug-check print statement */
}
Running it through the main with parameters file="somefile" pattern="somepattern" outputs the correct amount of somepatterns in the somefile as well as the typical migrating bug-checking print statement at the very end, after which it gets terminated for stack smashing.
Having read up on stack smashing, it seems like some end of the pipe is overextending a read or write into illegal space. I'm not sure where or why that's happening, however, since everything seems to work fine until function end. Other posts on here about stack smashing imply that it is the compiler throwing a canary into the code that signals failure when stack smash may happen. The problem is not with the main either. Can anyone shed any light on the situation?
Reference:
http://crasseux.com/books/ctutorial/Programming-with-pipes.html
Is where this code is mostly based off of.
The issue was not with the pipes. The issue had to do with the concatenation of strings to the empty string variable grep_str that clearly could not fit more strings in it. Credit to Paul and Rishikesh in the comments

C freopen() causes Segmentation Fault

I have a part of C program:
char buf[256];
fprintf(stderr, "buf created. going to freopen. Path:\n");
fprintf(stderr, path);
fprintf(stderr, "\n");
if (!freopen(path, "a", stderr)) {
fprintf(stderr, "if entered\n");
fprintf(stderr, "Can't redirect stderr\n");
sprintf(buf, "Server can't open log file (%s)", path);
fprintf(stderr, "sprintf ok. going to send_message\n");
send_message(buf, config.maintenance_delay);
fprintf(stderr, "send_message ok\n");
exit(1);
}
fprintf(stderr, "ndef USING_FCGI, ended\n");
And the output for it is:
buf created. going to freopen. Path:
../log_andrewwhynot/scheduler.log
Segmentation fault
So, I assume the problem is in the freopen() function but I'm unable to figure out what is wrong with it. I've double-checked the path to the file (it exists and everything is ok with access rights) and even tried to hardcode the absolute path or use path to another file, but everything was in vain. Then, I tried to open the file for write action instead of append, but it did not help as well. So, what might be wrong? Why does the call cause SIGSEGV?
Thank you!
Architecture: arm64
OS: armbian nightly 5.41.180312
gcc version: (Ubuntu GLIBC 2.23-0ubuntu10) 2.23

Using exec family for a perl script

I try to execute a perl script from my C program using a exec family function.
The first try with execv give me an infinite loop, so i check the man page for execv and see that all this function call execve which is more suitable for what i want to do.
Giving up to know why I have an infinite loop (yeah, that's not clever, i know), I intend to use execve, but this one fail too with "No such file or directory".
So i check again the man page, see that
[...]
filename must be either a binary executable, or a script starting with a line of the form:
#! interpreter [optional-arg]
For details of the latter case, see "Interpreter scripts" below.
[...]
ENOENT
The file filename or a script or ELF interpreter does not exist, or a
shared library needed for file or interpreter cannot be found.
So I write a code to check if both my perl scrip and the interpreter exist.
#define PERL_FILE "/home/path/script.pl"
int main(int argc, char *argv[], char *env[])
{
FILE *test;
char buffer[200];
/* Test if PERL_FILE exist */
if (!(test = fopen(PERL_FILE, "r"))) {
fprintf(stderr, "main : fopen("PERL_FILE") : %s\n", strerror(errno));
return (EXIT_FAILURE);
}
/* Retrieve the beginning of the PERL_FILE file */
if (fread(buffer, 1, sizeof(buffer), test) <= 0) {
fprintf(stderr, "main : fread : %s\n", strerror(errno));
return (EXIT_FAILURE);
}
fclose(test);
/* I want to check if the file in the shebang exist */
*strchr(buffer, '\r') = '\0';
printf("shebang = |%s|\n", buffer + 2);
if (!(test = fopen(buffer + 2, "r"))) {
fprintf(stderr, "main : fopen(%s) : %s\n", buffer + 2, strerror(errno));
return (EXIT_FAILURE);
}
fclose(test);
char *argv2[] = {PERL_FILE, NULL};
int i;
for (i = 0; env[i]; ++i) {
printf("%s\n", env[i]);
}
execve(PERL_FILE, argv2, env);
perror ("And so ... ");
return (EXIT_FAILURE);
}
Here the content of my perl script :
#!/usr/bin/perl
print "Hello world !\n";
and here the result of the code execution :
shebang = |/usr/bin/perl|
[...]
USER=root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SHELL=/bin/bash
[...]
And so ... : No such file or directory
(I edited in order to clean my env).
So all this lead to my question : what I'm doing wrong ?
Can't I execute a Perl script with a exec function family ?
I added a space between the shebang and the interpreter (like "#! /usr/bin/perl") but that fail too.
I succed with "system", but i musn't use it.
Thank for your reading.

Segfault occuring after a week of running?

I've got a C program which runs fine, but after around a week of running it always seems to segfault. I've compiled it with -g and run it through gdb and it looks like it pointing to the following code.
In my main loop I call a function (actually to try and debug why its crashing)
char config_debug[10];
I then read a conf file and based on the current setting in it, it sets config_debug to true
Then in my program I call this:
(line 312):
debug("send off data",config_debug);
This is the function:
int debug(char *debug_info, char *config_debug)
{
chomp(config_debug);
if ( strcmp(config_debug,"true") == 0 )
{
FILE *fp;
fp=fopen("/tmp/debug.log", "a");
(line 55):
fprintf(fp, debug_info);
fprintf(fp, "\n");
fclose(fp);
}
return 0;
}
void chomp(char *s) {
while(*s && *s != '\n' && *s != '\r') s++;
*s = 0;
}
Can anyone see anything wrong with the above 2 functions?
Here is a trace if it helps:
Program terminated with signal 11, Segmentation fault.
#0 0xb6d7a67c in vfprintf () from /lib/arm-linux-gnueabihf/libc.so.6 (gdb) bt
#0 0xb6d7a67c in vfprintf () from /lib/arm-linux-gnueabihf/libc.so.6
#1 0xb6d83cd8 in fprintf () from /lib/arm-linux-gnueabihf/libc.so.6
#2 0x0000a848 in debug (debug_info=0xc304 "send off data", config_debug=0xbec0cb5c "true") at station.c:55
#3 0x0000b614 in main (argc=1, argv=0xbec0cd94) at station.c:312
fprintf(fp, debug_info);
is wrong, and incorrect (possible undefined behavior) if debug_info contains a % (followed by some characters like s for instance).
You should read fprintf(3), enable all warnings in the cross-compiler e.g. by compiling with -Wall -g passed to your cross-compiler (clang would have warned you and gcc should, at least with -Wextra, but perhaps does not). In your case you could simply replace that faulty fprintf with a simpler and faster call to fputs(3) like:
fputs(debug_info, fp);
(in emebedded applications, fputs is often worth using, since it is faster than fprintf; actually sometimes the compiler optimize fprintf into something simpler.)
and replace the fprintf(fp, "\n"); with a simple putc('\n', fp);
BTW, it is confusing to have config_debug be both a global variable and a parameter. Avoid name collusions to improve readability. Be sure that config_debug and debug_info are null terminated strings.
fprintf(fp, debug_info);
fprintf(fp, "\n");
Above two statements are wrong.Modify Like this
fprintf(fp,"%s", debug_info);
fprintf(fp,"%s", "\n");
see fprintf()
From # Basile Starynkevitch comment, added.
You can also use fputs() and fputc() These are simpler and more efficient.
fputs(debug_info,fp);
fputc('\n',fp);

How to find the value of kernel.shmmax from C code

I want to get the value of kernel.shmmax in C code (which I query on centos5.0, centos6.0 and ubuntu10.04 using the shell command "$ sysctl -q kernel.shmmax").
I used the following code to find it:
#include <sys/sysctl.h>
const int SHM_ERROR=1;
main(){
int name[] = {KERN_SHMMAX};
int namelen = 1;
int oldval[1];
size_t oldlen = sizeof(oldval);
int rv = sysctl(name, namelen, (void*) oldval, &oldlen, NULL, 0);
if (rv!=0) {
fprintf(stderr, "while quering for shared memory size, sysctl returned error: %s\n", strerror(errno));
return SHM_ERROR;
}
else{
return 0;
}
}
After running the code above I get the following error:
while quering for shared memory size, sysctl returned error: Not a directory
I am clueless about why I am getting this error. I googled for it and found there is some issue with the paths into which library tries to look into.
I tried running the above code with GDB but the code doesn't steps into the function sysctl, otherwise I could have provided you more information.
Data point:
I am easily able to set and get kernel.shmmax from command line on all the operating systems mentioned using the following commands:
$ sysctl -q kernel.shmmax
$ sysctl -w kernel.shmmax=1000000000
Thanks
You shouldn't be calling sysctl from userspace code. From the man page:
Glibc does not provide a wrapper for this system call; call it using
syscall(2).
Or rather... don't call it: use of this system call has long been
discouraged, and it is so unloved that it is likely to disappear in a
future kernel version. Remove it from your programs now; use the
/proc/sys interface instead.
So give this a shot instead:
#include <stdio.h>
#define SHMMAX_SYS_FILE "/proc/sys/kernel/shmmax"
int main(int argc, char **argv)
{
unsigned int shmmax;
FILE *f = fopen(SHMMAX_SYS_FILE, "r");
if (!f) {
fprintf(stderr, "Failed to open file: `%s'\n", SHMMAX_SYS_FILE);
return 1;
}
if (fscanf(f, "%u", &shmmax) != 1) {
fprintf(stderr, "Failed to read shmmax from file: `%s'\n", SHMMAX_SYS_FILE);
fclose(f);
return 1;
}
fclose(f);
printf("shmmax: %u\n", shmmax);
return 0;
}
I install strace and see that sysctl looks at /proc/sys/kernel/shmmax with open() call instead of _sysctl() call or syscall() call.

Resources