Learning C

A couple months ago, Matasano Security published a set of cryptography challenges. I’ve been interested in crypto for awhile, so I decided to give them a go. I’ve also been wanting to get into lower level programming, and I took this as a chance to learn C a little better.

I’ve done a little bit of C here and there in the past (read through K&R, implemented some toy exercises), but I am by no means familiar. The following are a couple things that I’ve learned while working on these crypto challenges. Most of them are fairly obvious, but it was cool to see them play out anyway.

  1. C is fast. Really fast. There was a particular problem that I had difficulty solving in C, so I coded up a solution in Ruby so I could solve the challenge without worrying about using an unfamiliar tool-chain. The solution I wrote in Ruby takes 1.7 seconds to run. The solution I wrote in C takes 0.02.
  2. Managing memory is hard. Without language-level tools to guarantee that you’re not overrunning your buffers, it’s really easy to write to memory that you’re not supposed to. The symptoms of an overflowed buffer may not appear in obvious places, either. I had an issue where I got segmentation faults whenever I tried to malloc more memory. I was a little confused why a call to malloc would cause a segfault; it took awhile for me to realize that I had overflown a buffer further up.  Valgrind, a debugging tool and memory leak detector, was particularly helpful for these sorts of issues.
  3. gdb is awesome. I’d used gdb a little before when going through some other security related exercises, but I hadn’t used it more extensively until now. I’m used to writing Ruby or Python where an exception or failure results in an immediate stacktrace being printed to the console. C programs don’t do that for you unless you run them through gdb. It’s also good for looking at things in memory at breakpoints that you can set, although this is not much different from Python or Ruby debuggers.
  4. A lot of the difficulties in learning a new programming language are not actually related to the language itself, but the tool-chain. C is no different. I was not very familiar with GNU Make, so it took a little while to get used to the somewhat confusing syntax to get my project to work right. Building and Extending Gaim had a section on build tools that was quite instructive.
  5. As a Ruby web developer, I’m used to a very test-driven style of development. I couldn’t find standard unit testing tools for C that work similarly to how rspec or test/unit does, so I straight up did not write tests. This proved to be a little difficult to deal with, especially in an unfamiliar programming environment. I had a lot of bugs in random functions in disparate files that I didn’t know about until I ran them in specific scenarios. I ended up adding function calls to my main just to “unit test” my functions to see if they worked right, before deleting them again so as to actually run the code. In problem I mentioned above where I solved the challenge in Ruby first, I definitely wrote with TDD. It felt so much more secure than cowboy-coding in C.

C has been a great adventure so far; two more challenges before I finish the first set!

Advertisements

2 thoughts on “Learning C

  1. “C is fast. Really fast. There was a particular problem that I had difficulty solving in C, so I coded up a solution in Ruby so I could solve the challenge without worrying about using an unfamiliar tool-chain. The solution I wrote in Ruby takes 1.7 seconds to run. The solution I wrote in C takes 0.02.”

    Not only is ruby slow to run, but it is so high level that it makes writing inefficient code easier. Paying attention to performance and fine-tuning is more important when you’re writing the alogorithm, not so much when something in Enumerable does almost what you want with one opaque method call.

    “As a Ruby web developer, I’m used to a very test-driven style of development. I couldn’t find standard unit testing tools for C that work similarly to how rspec or test/unit does, so I straight up did not write tests.”

    When I did a lot of C programming in college, I had a lot of success writing test harnesses with bash that simply knew how to invoke my program and compare the outputs when given certain inputs. That definitely is more of an “acceptance test”, black box style of testing but it’s better than nothing.

    It might be a fun diversion to figure out how to test your C programs in ruby using something like fiddle.

    1. @phiggins, how much of ruby’s internals do you know? does that help you write more efficient code?

      that *would* be interesting, i wonder if anyone has written rspec with fiddle against C functions.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s