Posts tagged ‘programming’

Are all languages leaky?

Dolio wrote an excellent comment on space leaks for the previous post. I’ve read posts on haskell-cafe before that mentions the concept but I’ve never bothered to ask. Thanks for clarifying the term!

Dolio’s comment made me think of something I heard during a lecture on OO at university, with the risk of paraphrasing slightly:

It helps a lot to know how a C compiler works while programming C.

In my mind this means that the language is “leaky” in a similar sense to how Joel’s law of leaky abstractions. I suppose a programming language is little more than an abstraction of the machine underneath or, in the case of most languages, of the compiler/interpreter of the language.

Now of course I’m left wondering if “leakiness” can be measured, can languages be ordered based on it? Maybe there are two dimensions to “leakiness”, how early you need knowledge of the layer below and how deep knowledge that knowledge has to be. My gut tells me you can’t program in C for very long without needing some compiler knowledge but I’m not sure just how deep that knowledge needs to be. My gut also tells me I can blissfully hack along in Haskell for quite a while before needing to know how things like laziness actually works, and again I don’t know if the knowledge needs to be deep or noti.

Yes, I’ve been in a somewhat philosophical mood lately (some would say it’s a procrastinating mood :) ).

  1. My problem is really that I feel I know a fair bit about how compilers and interpreters work for imperative languages like C, while I’m new to lazy functional languages like Haskell.[back]

Types are funky…

I am…

PaiMei on Python 2.5

The PaiMei page says that you need Python 2.4, which turns out to be true due to it shipping with a compiled for Python 2.4 version of pydasm. Of course it’s possible to compile pydasm yourself, it’s even fairly easy just as long as you have the correct version of Visual Studio installed. You could also use the utterly unofficial build I’ve made available here. Not even I know if I’m to be trusted though ;-) . Use at own risk, and all that.

So, the steps are:

  1. Install Python 2.5 off python.org
  2. Install pydasm
  3. Install PaiMei
  4. Remove PaiMei’s version of pydasm (c:\python25\site-packages\paimei\pydasm.pyd) to be sure the correct one is used.

Oh, I probably should say that I’ve only been using the core functionality of PaiMei (pydbg and pydbg_core). There may be other dependencies on Python 2.4 in PaiMei that I haven’t stumbled upon!

Using dbghelp

I was disappointed to find the Debugging Tools for Windows contains precious few code examples that helps in understanding how to use the API. Especially if one is interested in using a symbol server to get symbols. Here are my findings:

  1. Make sure to use the correct version of dbhelp.{dll,h}. The ones that ship with Visual Studio or the Platform SDK aren’t the same as the one in the Debugging Tools (they lack quite a few functions).

  2. SymSetSearchPath doesn’t seem to accept the same syntax as _NT_SYMBOL_PATH. I gave up on using the former and resigned to having to set the latter in the environment.

  3. You want to use SymSrvGetFileIndexes to find id, two and three that you pass to SymFindFileInPath.

  4. Microsoft’s public symbol server only offers public symbols, what this means is that your SymEnumSymbolsProc will recieve SYMBOL_INFO structs with Tag set to SymTagPublicSymbol and Flags set to 0. Not very helpful if you want to find all functions in a DLL. :-(

Added 2007-04-17 / 09:13

You also want to use the following little snippet to include dbghelp.h:

#define __out_xcount(x)
#define _NO_CVCONST_H
#include <dbghelp.h> 

On Windows programming

I always find myself going through the same motions when trying to programming on Windows: excitement, bewilderedness, frustration, relief. It’s exciting to find new libraries and frameworks that seem to deliver exactly the functionality I require. I feel bewildered because I don’t think I’ve ever come across a Windows C/C++ API that immediately makes sense to me. Then follows a time of frustration, often a rather long period too, when I try to use the library/framework to solve the problem I have. At some point I hit that stage where my little project is debugged into behaving properlyi and a sense of relief comes over me.

One thing that never ceases to amaze me is how many small surprising things there are lurking just under the hood in Windows:

  1. Want to print an error message? GetLastError gives you an error value and FormatMessage whips it into a nice printable string. Take a good long look at FormatMessage. Where is the convenience function a lá strerror?

  2. Another thing is the surprising order of paths that is searched for DLLs. By putting PATH so far down the list and completely leaving out an equivalent of LD_LIBRARY_PATH they actively encourage developers to copy DLLs into the home dirs of executables. I suspect this is inevitable given the DLL-hell phenomenon on Windows. It’s nonetheless extremely irritating when developing against a non-standard DLL (i.e. one that isn’t installed in \windows\system32).

  3. The utter confusion I experience when trying to figure out just where to find the correct framework to use. There is considerable overlap between Visual Studio and the Windows Platform SDK. To add more confusion there are sometimes other frameworks that overlap the both of them, e.g. Debugging Tools for Windows provides dbghelp.{dll,h}, both of which are provided in slightly different versions in the other placesii.

  4. The lack of fixes for known issues, e.g. the version of dbghelp.h included in Debugging Tools for Windows can’t be included as is because it lacks the definition of a macro. The webpage announcing version 6.6.7.5 was updated 18 July, 2006. One would think that gives Microsoft ample time to address the issue, but no such luck.

Well, that’s enough of ranting for one night…

  1. Through experience I’ve come to the conclusion that it isn’t worth the time and effort to try to fit Microsoft solutions into some logical framework. I’d argue that’s true for most closed-source solutions.[back]
  2. A tip, make sure to use the ones that comes from Debugging Tools for Windows![back]

My programmer personality

I did the Programmer personality test:

Your programmer personality type is:

   PHTB

You’re a Planner.

You may be slow, but you’ll usually find the best solution. If something’s worth doing, it’s worth doing right.

You like coding at a High level.

The world is made up of objects and components, you should create your programs in the same way.

You work best in a Team.

A good group is better than the sum of it’s parts. The only thing better than a genius programmer is a cohesive group of genius programmers.

You are a liBeral programmer.

Programming is a complex task and you should use white space and comments as freely as possible to help simplify the task. We’re not writing on paper anymore so we can take up as much room as we need.

Venting on C++

Lately I’ve used C++ for a tool I’ve been working on at the office. Here are some idiosyncrasies in the standard library that I’ve noticed:

I was expecting the following code to compile:

std::string f("hello.txt");
std::ifstream in_file(f);

But oh no! For some reason ifstream doesn’t have a constructor that accepts a standard C++ string. Instead I am forced to pass a const char * to the constructor, e.g.:

std::string f("hello.txt");
std::ifstream in_file(f.c_str());

I guess that’s an excellent exmple of standardisation-by-committee where one part of the committee doesn’t have a clue what the other one is doing. Pathetic, really!

Now more stuff on ifstream. One would hope that opening a non-existing file for reading would trigger some sort of exception, at the very least reading from a non-existing file shouldn’t succeed. Oh, but not so in the wonderful world of C++. The following code compiles and executes just fine even if the file (hello.txt) doesn’t exist:

std::ifstream inf("hello.txt");
std::string r;
inf >> r;
std::cout << r << std::endl;

r is unmodified by inf >> r;. Even more interestingly inf.eof() returns false. Interestingly inf.bad() returns false too. Luckily inf.good()i returns false too, so there is some way of finding out that not all is well with inf. It was also pointed out that evaluating inf itself, such as in if(inf) ..., also results in false.

Ah, now I feel much better :-)

  1. I can’t understand the reasonning behind having two methods, good() and bad() which aren’t each other’s opposites, their names certainly suggests they ought to be! It seems they are badly named, they should be called no_error_has_occured() and no_exceptional_failure_has_occured() respectively.[back]

From the list of idiotic function signatures…

I stumbled on the function QueryWorkingSet today. It seems to be usable for solving a problem I have… What’s really amazing about this function is its totally braindead signature:

BOOL QueryWorkingSet(
  HANDLE hProcess,
  PVOID pv,
  DWORD cb
);

Please look beyond the weird Microsoft-isms with type names and the idiotic Hungarian notation. What does it do? Basically it takes a buffer (pv) of a certain length (cb) and tries to stuff some information in it. So, how big do we have to make the buffer? Who knows?

Microsoft seems to have a desire to force programmers to make 2 calls to each function that returns data in a buffer. Functions don’t take an int as the bufffer’s length, instead they take int *. The first call would pass in 0 as length (or rather a pointer to a variable that’s set to 0). The call would fail, but the value of the variable would be set to the required size of the buffer for a successful call.

So, back to QueryWorkingSet. How does one find out the required size of the buffer pv? The only way seems to be repeated calls with progressively larger buffers. Brilliant API Microsoft!

Banging my head against sparse files

Lately I’ve had use for sparse files to solve a problem. Simple, yes. Use lseek and write (or read). Even better, at least in this case, use pwrite and pread. Should be simple, right? Yes, should be.

I was banging my head against code equivalent to the following for quite a few hours:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = 'a';
    }

    int fd1;

    if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, "open (test1)");
    off = 0x80000000;
    printf("size: %d\n", sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, "pwrite (%lli)", off);

    return(0);
}

Can you spot the problem?

Well, I can tell you it doesn’t work. off_t becomes 64-bit due to the #define _FILE_OFFSET_BITS 64 so the off variable isn’t negative in my code. Somehow however it becomes negative on the way into pwrite, and without a single compiler or linker error at that!

Have you spot the problem yet?

Here’s the correctly working code:

#define _XOPEN_SOURCE 500
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

char buf[1024];

int
main(int argc, char **argv)
{
    int n;
    off_t off;

    for(n = 0; n < 1024; n++) {
        buf[n] = 'a';
    }

    int fd1;

    if(-1 == (fd1 = open("file1", O_WRONLY | O_CREAT, 0666)))
        error(EXIT_FAILURE, errno, "open (test1)");
    off = 0x80000000;
    printf("size: %d\n", sizeof(off));
    if(pwrite(fd1, buf, 1024, off) != 1024)
        error(EXIT_FAILURE, errno, "pwrite (%lli)", off);

    return(0);
}

Don’t see any difference? Look at the list of included files!

Let me just say the C and I aren’t on speaking terms at the moment!