Barnoid’s Knowledge Base

Bits of Collected Wisdom

November 5th, 2008

1001 reasons why C/C++ is evil

Consider the following C++ code:

class A
{
int do(string key, bool b)         { cout << "do('" << key << "', " << (b ? "true" : "false") << ")" << endl; };
int do(string key, string value) { cout << "do('" << key << "', '" << value << "')" << endl; };
};

...

A *a = new A();
a->do(”do”, “something”);

What is printed? Well, not what I expected:

# ./reason1
do('do', true)

Intuitively, the second method, do(string string), should be executed, but gcc (4.1) executes the first method, do(string, bool). This is because the second ’string’, “something”, is interpreted as ‘char *’.

One down, 1000 more reasons to come.

April 21st, 2007

vmplayer on Gentoo Linux 2.6.20

If vmplayer fails to compile on your 2.6.20 kernel with the following error

Extracting the sources of the vmmon module.

Building the vmmon module.

Building for VMware Player 1.0.2 or 1.0.3 or VMware Workstation 5.5.2 or 5.5.3.
Using 2.6.x kernel build system.
make: Entering directory `/tmp/vmware-config1/vmmon-only'
make -C /lib/modules/2.6.20-gentoo-r6/build/include/.. SUBDIRS=$PWD SRCROOT=$PWD/. modules
make[1]: Entering directory `/usr/src/linux-2.6.20-gentoo-r6'
CC [M]  /tmp/vmware-config1/vmmon-only/linux/driver.o
In file included from /tmp/vmware-config1/vmmon-only/linux/driver.c:85:
/tmp/vmware-config1/vmmon-only/./include/compat_kernel.h:21: error: expected declaration specifiers or ‘...’ before ‘compat_exit’
/tmp/vmware-config1/vmmon-only/./include/compat_kernel.h:21: error: expected declaration specifiers or ‘...’ before ‘exit_code’
/tmp/vmware-config1/vmmon-only/./include/compat_kernel.h:21: warning: type defaults to ‘int’ in declaration of ‘_syscall1’
make[2]: *** [/tmp/vmware-config1/vmmon-only/linux/driver.o] Error 1
make[1]: *** [_module_/tmp/vmware-config1/vmmon-only] Error 2
make[1]: Leaving directory `/usr/src/linux-2.6.20-gentoo-r6'
make: *** [vmmon.ko] Error 2
make: Leaving directory `/tmp/vmware-config1/vmmon-only'
Unable to build the vmmon module.

change dir to /opt/vmware/player/lib/modules/source and untar vmmon.tar

# cd /opt/vmware/player/lib/modules/source/
# tar xvf vmmon.tar
vmmon-only/
vmmon-only/autoconf/
vmmon-only/autoconf/geninclude.c
vmmon-only/autoconf/epoll.c
...

next, edit the file vmmon-only/include/compat_kernel.h and add the following preprocessor statements (in bold font)

/*
* compat_exit() provides an access to the exit() function. It must
* be named compat_exit(), as exit() (with different signature) is
* provided by x86-64, arm and other (but not by i386).
*/
#define __NR_compat_exit __NR_exit
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
static inline _syscall1(int, compat_exit, int, exit_code);
#endif

save, exit the editor, rename the original tarball and create an updated vmmon.tar tarball:

# mv vmmon.tar vmmon.orig.tar
# tar cvf vmmon.tar vmmon-only

now run vmware-config.pl again

# /opt/vmware/player/bin/vmware-config.pl
...
The configuration of VMware Player 1.0.3 build-34682 for Linux for this running
kernel completed successfully.

You can now run VMware Player by invoking the following command:
"/opt/vmware/player/bin/vmplayer".

Enjoy,

--the VMware team
September 20th, 2006

On Pipes and Forks: Read (uncompressed) data directly from compressed files

Sometimes you’ve got data in a compressed form, but you need to read and process the (uncompressed) data in a program. If, as in my case, the uncompressed data (a program execution trace) is around 8 GB, and the compressed trace only 400MB big, uncompressing that data to disk, reading it and, after processing, deleting it is a big hassle.

It would be nice to directly uncompress and read the data from within the program…and luckly this is actually very simple:

Let’s say, we have a compressed file, trace.dat.gz, then we need to read from.

The code to read the decompressed data goes something like this:

FILE *trace = fopen(filename, "r");

while ((res = fscanf(trace, "%s "lx %lx", &status, &adr, &data)) == 3) {
    /* process data */
}

fclose(trace);

The trick to directly read from the compressed file is to execute a process that decompresses the data and directly feeds it into our program. That’s what pipes & fork are for:

int pfd[2];
FILE *trace = NULL;
if (pipe(pfd) != 0) return false;
pid_t cpid = fork();
if (cpid == 0) {
    // child process: redirect pipe to stdout & start the decompressor
    close(pfd[0]); dup2(pfd[1], 1); close(pfd[1]);
    excelp("gunzip", "gunzip", "-c", filename, NULL);
    exit(0);
} else {
    // parent: read from the pipe
    close(pfd[1]);
    trace = fdopen(pfd[0], "r");
}

while ((res = fscanf(trace, "%s "lx %lx", &status, &adr, &data)) == 3) {
    /* process data */
}

fclose(trace);
close(pfd[0]);

That’s it! Our program now automatically runs “gunzip” on the compressed data before piping it into our program.