Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Refactoring C Code: Multi-Platform and Valgrind

DZone's Guide to

Refactoring C Code: Multi-Platform and Valgrind

Learn how to create a cross-platform network secure using C, OpenSSL, and few other interesting tools.

· Web Dev Zone ·
Free Resource

RavenDB vs MongoDB: Which is Better? This White Paper compares the two leading NoSQL Document Databases on 9 features to find out which is the best solution for your next project.  

I decided that it is time to take my network protocol and make it cross platform, so I tried to compile it on the Linux subsystem for Windows. As an aside, the fact that I could edit everything in Visual Studio while compiling using GCC and having immediate feedback is amazing, given the usual workflow that this entails. And I would very much like to hear about an IDE that is comparable to Visual Studio out there.

I got to say, the situation for dependencies on C/C++ is flat out horrible. I’m depending on OpenSSL for this code, and I have used VCPkg for actually setting up the dependency. On WSL, on the other hand, the OpenSSL packages are from 2014(!), so they were incompatible. I recompiled the lastest stable on WSL and tried to get it to work. It didn’t, first it didn’t put the new code in the right place and when I forced it to use the right paths, it failed with missing methods. It looks like I’m spoiled from the point of backward compatibility, but several methods have been deprecated or flat our removed.

I fixed that stuff only to find out that what the WSL version requires is actually newer than what the OpenSSL version I have on the Winodws machine has. I could compile the latest on Windows as well but for now it was just easier to conditional compile the stuff that I needed. I find it sad, but I want to get things done.

After a lot of grunt work, I’m happy to say that this looks like it is actually working. You can find the code for that in this link. I also wrote a small bit of C# code to connect to the server, which looks like:

var tcpClient = new TcpClient();
await tcpClient.ConnectAsync(IPAddress.Loopback, 4433);
using (var stream = tcpClient.GetStream())
using (var ssl = new SslStream(stream, leaveInnerStreamOpen: false,
    userCertificateValidationCallback: 
        (object sender, X509Certificate certificate, 
         X509Chain chain, SslPolicyErrors sslPolicyErrors) => true
         ))
{
    var cert = new X509CertificateCollection();
    cert.Add(new X509Certificate2(@"example.p12"));
    await ssl.AuthenticateAsClientAsync("example.com", cert, checkCertificateRevocation: false);

    var writer = new StreamWriter(ssl);
    var reader = new StreamReader(ssl);

    while (true)
    {
        Console.WriteLine(reader.ReadLine());
        var str = Console.ReadLine();
        writer.WriteLine(str);
        writer.Flush();
    }
}

I got to admit, the difference in the lines of code and complexity between the two code bases is pretty staggering.

I aso have to admit, I had an ulterior motive behind wanting to run on Linux, I wanted to see just how badly I managed to manage memory in this short bit of C code, and Valgrind is one of the more common tools to do that.

Of course, Valgrind doesn’t run on WSL, so I had to build that from source as well. I have to say, I was really careful about the actual memory usage and freeing everything. Valgrind was still able to find an issue within the first two minutes of me running it. I got to say, I’m really impressed. Here is the leak:

image

As you can see, this is happening because I’m using client certificates and it is deep inside OpenSSL (narrator voice: it wasn’t a problem with OpenSSL).

This was a bit of a problem to try to figure out, because I was really careful and properly match each allocation call with the call to release it (in this case, SSL_new() with SSL_free()). I went over the code to establish and tear down a connection many times, but couldn’t see any problem.

The issue here is that Valgrind, in this case, shows me where the memory was allocate, but the leaks is actually elsewhere. OpenSSL implements reference counting for many objects, and as part of the client certificate usage I’m getting the client’s certificate and examining it. In the act of getting the certificate to increment the ref count on that certificate, I have to explicitly release that certificate once I’m done with it. Naturally Valgrind wasn’t able to figure all of that and just told me that I actually have a leak.

Lesson learned, look at the allocation stack, but don’t marry it or assume it is known correct. Here is the latest drop of code, which is able to pass Valgrind with no leaks detected.

Get comfortable using NoSQL in a free, self-directed learning course provided by RavenDB. Learn to create fully-functional real-world programs on NoSQL Databases. Register today.

Topics:
web dev ,network security ,cross-platform networks ,c tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}