Archive | ghc RSS for this section

K&R Challenge 2: The Specter of Undefined Behavior

Continuing with the K&R Challenge, today we’ll be doing exercise 2:

Experiment to find out what happens when printf‘s argument string contains \c, where c is some character not listed above.

Basically, we’ll be trying to print “\c” to the screen, and seeing what C does.

In C

The code for this is very simple:

int main (int argc, char ** argv) { printf("Trying to print: \c\n"); return 0; }

Like last time, we’ll compile it using:

gcc -Wall ex2.c -o ex2

Right away, you should get a compiler warning:

ex2.c: In function ‘main’: ex2.c:10:11: warning: unknown escape sequence: '\c' [enabled by default] printf("Trying to print: \c\n");

Notice that it is a warning, not an error, and that the compilation still succeeded and produced an executable. My friends, you have just witnessed Undefined Behavior. Undefined behavior is one of the defining aspects of C. Technically, it’s a feature, not a bug, and it is both a blessing and a curse.

It’s a blessing in that it’s one of the things that enables C’s unmatched performance. It’s a curse in that the compiler is allowed by the spec to do whatever it wants when it encounters undefined behavior: it could do something really helpful, it could segfault, or it could delete your hard drive. It could even unleash lions in your house and there’s nothing the police or congress could do about it.

Moral of the story: don’t use undefined behavior unless you really know what you’re doing. Even then, I’d argue it’s a code smell.

So, what happens when you run the compiled executable? Always fearless in the pursuit of truth, I ran it. The following was printed to the console:

Trying to print: c

The GNU C Compiler decided to be nice and just strip the “\”, then print the message. It’s a good thing I have managed to avoid angering Richard Stallman, because gcc could very well have kidnapped my wife. That would have been a problem.

And In Haskell

Nothing about this exercise relies on the behavior of printf, therefore even though Haskell has it, I’ve elected not to use it. The implementation of this exercise in Haskell looks like this:

main :: IO () main = putStrLn "Trying to print: \c\n"

As before, this can be run using:

runhaskell ex2.hs

…but when you try it, the following error is displayed, and compilation fails:

ex2.hs:2:62: lexical error in string/character literal at character 'c'

Where C allowed the undefined escape sequence as undefined behavior, Haskell throws a compilation error. This is a Good Thing. Undefined behavior is a prolific source of bugs, and while I understand why it’s allowed, I can’t say that I agree that the tradeoff is worth it. Luckily for us, this isn’t a feature unique to Haskell. Most high level languages don’t have undefined behavior. Unfortunately, this is one of the reasons that most programming languages are orders of magnitude slower than C.

Regardless, undefined behavior is a fact of life for the C programmer. It’s one of the tradeoffs they make to use the language. These design decisions were made decades ago, and are unlikely to change. For this reason, this is a good exercise.

The families of those who were turned to stone by their compilers after doing this exercise are in our prayers…

Introducing The K&R Challenge

Recently, I inherited a copy of The C Programming Language, aka “K&R”. I was borrowing it, and today I tried to give it back, but the book’s former owner didn’t want it back. I was going to put it back in it’s deep dark box, likely to never been seen again, when I had a thought. Surely there’s something in this ancient tome of knowledge waiting for me.

On a whim, I decided to go through the exercises. This post marks the first task in the K&R Challenge.

The rules: the book is about the C programming langauge. The book is not about glib, linux programming, gtk, or any other library or framework. Therefore, the solutions to the exercises should only use the standard library, unless the book specifically calls out a library. I will attempt to stay as true to the wording of the excercise as possible.

Seems pretty straightforward, right? Well this brings us to part two; after doing an excercise in C, I will do it in Haskell. For these examples, I will attempt to implement the program in idiomatic Haskell. The ends are more important than the means here, so if the example calls out a specific function or technique, I will only use it if I feel it’s the best way to do it. For the Haskell portion, I will minimize the use of libraries as well.

So, without further ado…

Excercise 1.1

Excercise 1.1 is simply to implement “Hello World” Shockingly this is a trivial problem in C:

#include "stdio.h" int main (int argc, char ** argv) { printf("Hello World!\n"); return 0; }

First, we include stdio.h to gain access to printf, then we say hello to the world. You’ll notice I put curly braces on their own lines. Sue me.

To compile this, assuming you’re using gcc, enter the following:

gcc -Wall ex1.c -o ex1

Running the produced program produces the output:

Hello World!

Amazing!

In Haskell, this is even easier:

main :: IO () main = putStrLn "Hello World!"

As putStrLn and the IO monad are in prelude, this program does not require any imports.

To run this, simply type the following at the prompt:

runhaskell ex1.hs

Which produces the following output:

Hello World!

If you were able to follow all of that, then congratulations! You are an elite hacker! Your black fedora is in the mail.

Doesn’t Play Nice With Others

For the last few weeks, I’ve been looking into making a Printer Module in Haskell. I must say, it’s been a pretty miserable experience. Not the Haskell part, that was ok. No, my issue is more basic. It seems that Haskell doesn’t like to share.

My plan was to build a module in Haskell to do the printer logic, then link that module as a library into C, which will be imported by the Core as normal. A preliminary look about the internet confirms that this is supported behavior. There are a few trivial examples peppered throughout the internet; so I set to work, confident that this was a solvable problem.

Giving Cabal A Shot

Cabal is Haskell’s package management program. In addition to this, it serves as Haskell’s answer to make. With a simple call to:

cabal init

You are presented with a series of questions about your package. After filling out the form (and selecting library), Cabal creates a Setup.hs file. Calling:

runhaskell Setup.hs configure runhaskell Setup.hs build

…produces a .a library for your package. Success, right? Unfortunately when you try to load that you get a linker error stating something to the effect of “can not be used when making a shared object; recompile with -fPIC“. After hours of research I have determined that this is because the Haskell’s libraries have not been compiled using the -fPIC, which prevents them from being used with a static library.

Trying GHC

The Glasgow Haskell Compiler can be used to compile libraries directly. Having given up on cabal, I decided to try to cut out the middle man and use GHC. After much tinkering, I came up with a Makefile that worked, which I will preserve here for posterity:

COMPILER=ghc HS_RTS=HSrts-ghc7.6.3 OUTPUT=dmp_printer_module.so all: "${COMPILER}" --make -no-hs-main -dynamic \ -l${HS_RTS} -shared -fPIC dmp_printer_module.c \ DmpPrinterModule.hs -o ${OUTPUT}

This makefile compiles any required Haskell scripts, as well as a C “glue” source file that initializes and finalizes the Haskell environment. More on what goes in that file can be found in the GHC documentation.

Cool, good to go, right? Wrong.

Couldn’t Find That Dyn Library

So, I started adding things to the module to make sure it doesn’t break. After adding some dependencies, and trying to recomplie, I start seeing this error:

Could not find module `[SOME_MODULE]' Perhaps you haven't installed the "dyn" libraries for package `[SOME_PACKAGE]'?

After more hours of research, it turns out that for a module to be used in a shared library, it must be compiled as one. Seems logical, but that would imply that all module developers have to go through this nightmare. And the developers of any dependencies they use have to have done so. And so on…

Since even Prelude hadn’t done so, I set off to figure this out. After poking about, it turns out that Debian provides a package ghc-dynamic, which provides the dyn libraries from Base. I installed it, and things were checking out. However, the dependencies I was using still did not work.

After some more reasearch, I found a suggestion that I re-install all my Cabal packages using the --enable-shared flag, which would provide me with my dyn libraries. I gave it a shot, but since my dependencies’ dependencies hadn’t done so, I got the same errors.

Some more research suggested that I could delete the .ghc folder in my home folder, then re-install all Cabal packages. This would force them to rebuild. However, I encountered the same issues.

The Man In Black Fled Across The Desert…

I’m beginning to feel a bit like Roland, ceaselessly chasing after the Dark Tower. Every time I get there, my journey starts over again. I clear one roadblock, and there’s another there waiting for me.

It seems like there isn’t any real interest in calling Haskell from C, and I must say that I am extremely disappointed. Calling C from Haskell works great, but when asked to share its toys with C, Haskell takes its ball and goes home.

I’m sure it’s possible to do meaningful work in Haskell, and call that from C. However, the amount of work I would have to do to attain that goal is not something I’m willing to accept. For this reason I am shelving Haskell for the time being. Maybe I’ll pick it again for some other project, but it’s not a good fit for DMP Photo Booth.

%d bloggers like this: