The software security argument why Ledger Recover is a security risk

Introduction

Ledger has rolled out a "feature" where users can store their Ledger Nano seed-phrase remotely against a payment of $10/month. The feature allows for extracting an encrypted seed-phrase of cryptocurrency outside the hardware wallet! This has led to too much controversy. Some people think it's the cool thing to give Ledger a break after endangering people's money to make money off its users. Besides that ledger admitted that a government Subpoena can lead to handing over cryptocurrency to government with this feature, there's a technical argument why this is inexcusable.

It's attractive to just say "I'm outside the hive-mind, and hence ledger did nothing wrong, or that the security model is unchanged", but this misses the whole point of why Ledger Recover is a problem, from a software security point of view.

As a software engineer who deals with systems programming languages, there are lots of misconceptions about this whole debacle. Even the former Ledger's chairman seems to skip this point and claim it's just a trust issue. I'd like to explain the nuance as an expert who dealt with these issues and worked in this field for 15 years.

It's not about trusting or not trusting ledger

Even if we trust ledger 100%, the problem I'm about to describe isn't related to that. The problem is: We're all humans, and human software engineers all do the same mistakes… we have over 50 years of experience in that.

All software has bugs, and that's the problem

Over the course of humanity writing software, we learned how bugs happen, how bugs appear in the code, and how little control we have over them. The ledger software is most likely written in C, which is the language that's most vulnerable to these kinds of issues. If you'd like to see how dumb, little bugs can lead to compromising the whole machine, I recommend PwnFunction's video "Dangerous Code Hidden in Plain Sight for 12 years". It's an 18 minutes video with a great example in Linux and how a dumb mistake lead to exploits in Linux, including unprivileged root access. Doesn't matter how arrogant software engineers are, they do dumb mistakes, because they're human. We all do.

This problem is so bad, that there's a (relatively) new programming language that advertises that it solves lots of the memory issues that programming languages like C and C++ easily allow. It's called Rust, you probably heard about it. It's not a silver bullet, but it tries to solve most of these issues… and we're not done yet with this problem. That's a topic for another day.

But how can an attacker exploit Ledger Recover?

We don't know, and that's the scary part. If we knew, we would've fixed it, right? But I'll give you an introduction into how these bugs happen and how they're exploited.

Here's an example in the next section… in a nutshell, without going into too much details.

Programs are dumb counters, and bugs allow hackers to exploit them

When you start a program (whether in Ledger or on your PC or otherwise), the operating system maps your program to memory, and runs what's called a Program Counter. The program is just a dumb counter that is incremented. If your system is 32-bits (CPU instructions are 4-bytes wide), and your program is mapped to start at byte number 10000 in the memory array, then the counter simply is incremented on every instruction: 10000, then 10004, then 10008, then 10012, etc. And on every increment, the CPU reads the instruction in memory and executes the instruction in there.

(for the "actually" people, I'm leaving out tons of details such as caching… but let's keep this simple).

In all CPU architectures, there's an instruction called the "jump" instruction. The jump instruction gives the CPU a new address in memory to "jump" to, where the program counter changes its value, so that different code is executed, like in conditional statements… "if this is larger than that, do this, or do that".

Functions and jumps + bugs = disaster

A function, in programming, is defined as a group of instructions/functionality that's grouped in one place in memory (again, simplification). This is one of the jobs of a jump instruction… to do "function calls", and run a group of instructions when necessary.

What can happen is that a software has something called a buffer-overflow bug. Buffer-overflow basically gives the program access to other sections in memory it's not supposed to access. This is, kind-of, the main cause of problems in C programming.

If you're old enough in Cryptocurrency, remember when EOS had a bug that was discovered by a security company that allowed for remote code-execution? That was a buffer-overflow.

If a hacker discovers a buffer overflow, they can write jump instructions, for example, to force the program to call functions it's not supposed to call… say… call the function that extracts the seed-phrase and pass it through USB? Or maybe skip the encryption function and make it an identity function that does nothing? That's the problem.

"It's a new attack vector"

When Ledger writes a function in the firmware that extracts the seed phrase, they basically gifted all hackers a function they can try to reverse-engineer, and see if they can abuse it due to some bug a ledger engineer created, just like all humans have been writing bugs for the last 50 years. That's why people are saying "it's a new attack vector".

To Ledger staff: You're not gods. You're humans. Just like us. We all write bugs, and you're not an exception.

That's why a firmware without this functionality at all is valuable.

How to backup and end-to-end encrypt your remote server data without manually inputting a password

Introduction - The problem

The problem is the following: You run some service where you need to have regular backups. The data to be backed up can be represented as something you can put in a tarred archive. The common way to do this is to pipe the tar output to OpenSSL and encrypt with AES-256, which is fine, except that it requires inputting the password constantly or putting a static password on the server. If you've guessed that we're going to use public key cryptography, you're right, but there is a problem there.

The typical way of doing this with passwords

If you research this topic online, you'll find the internet flooded with solutions that look like this:

$ tar -czpf - /path/to/directory-to-backup | openssl aes-256-cbc -salt -pbkdf2 -iter 100000 -pass | dd of=output.aes

There are a few problems with this… let me state them and let's see whether we can do better:

  • You have to input the password manually for this to work, so this cannot go into a cron/periodic job unless you expose the password
  • Since you have to put the password manually, it has to be some text, which lacks entropy, given that pbkdf2 (as far as I know) uses SHA256; where if you know anything about bitcoin mining, you'll know that SHA256 calculations have become very cheap… meaning that your password that you write with your hand, most likely, lacks entropy for security
  • It uses AES-256-CBC, which lacks authentication… but let's not get into that since OpenSSL has support issues for the better alternative, GCM, but I'll provide a simple solution to this at the end

Let's see if we can do better.

How can public key cryptography solve these problems?

Introduction to public key cryptography

Feel free to skip this little section if you know what public key crypto is.

We call symmetric key cryptography, the kind of cryptography where the encryption and decryption, or signing and verifying, uses the same key. In public key cryptography, or asymmetric key cryptography, we use the public key to encrypt data, and private key to decrypt data. Or we use the private key to sign data, and public key to verify signatures.

But public key encryption doesn't really help as a replacement

It may be a surprise, but there's no way to encrypt large data with public keys. The reason for this is that encryption algorithms usually are either done in blocks (like in AES), or in streams (like Chacha20). Public key encryption that we have is either considered a block cipher (like RSA encryption), or is used to generate symmetric keys using some agreement protocol, like Diffie-Hellman, which then uses symmetric encryption. And given that RSA encryption is very expensive, because it's an exponentiation of a large number, it's not really practical to use it for large data, so no standard algorithms are found in software like OpenSSL to encrypt your backups. You'll never see RSA-4096-CBC or RSA-4096-GCM for that reason.

How then do we encrypt without a password?

The trick is simple. We generate a truly random password, encrypt the password with RSA and store it in a file, use the password for encryption, then we forget the password and move on. The password then can only be recovered with a private key (which will be encrypted). Let's see how we do this.

First, in your local machine where you're OK with unpacking the data, generate your RSA keys. Generate your decryption private key (encrypted with a passphrase):

$ openssl genrsa -aes256 -out priv_key.pem 4096

and from that, generate your public key

$ openssl rsa -in priv_key.pem -outform PEM -pubout -out pub_key.pem

Now this password that you use to encrypt this key will be the only password you'll ever type. Your backups don't need it.

Now copy the pub_key.pem file to the remote machine where backups have to happen.

If you have a backup bash script, you can do the following now:

#!/bin/bash

# generate a random password with 256-bit entropy, so PBKDF2 won't be a problem
password=$(openssl rand -hex 64)

# tar and encrypt your data with the password
tar -czpf - /path/to/directory-to-backup | openssl aes-256-cbc -salt -pbkdf2 -iter 100000 -pass pass:${password} | dd of=output.aes

# encrypt the password using your RSA key, and write the output to a file
echo ${password} | openssl rsautl -encrypt -inkey pub_key.pem -pubin -in - -out output.password.enc

To view the password in that file, you can view it in stdout using this command:

$ openssl rsautl -decrypt -inkey priv_key.pem -in output.password.enc -out -

This will print the password to your terminal, which you can copy and use to decrypt your encrypted archive.

Finally, to decrypt your data, run the command:

$ dd if=output.aes | openssl aes-256-cbc -d -salt -pbkdf2 -iter 100000 | tar -xpzf -

and when asked, input the password you copied from the private key decryption of the command before

WARNING: It's WRONG to use the same password and encrypt it again and again and again with RSA (with this scheme, at least). Be aware that encrypting the same password with the same public key will yield the same output. This means that someone with access to the encrypted files can recognize that you're using the same password everywhere.

Conclusion

No need, anymore, to choose between encrypting your backups and not being there. You can have both with this simple trick. This is also more secure because the 256-bit password generated randomly can never be brute-forced through the cheap pbkdf2, which basically means that brute-forcing the encryption itself is cheaper than brute-forcing the password that derived the key, which will guarantee the 256-bit encryption strength.

Now about using CBC instead of GCM, you can create your own HMAC to authenticate your archives. Or, even easier, you can call sha256sum on your archive and encrypt the output with your public key or even sign it. That's good enough and can be streamlined into anything you automate for your backups.

I just wanna mention also that this isn't an innovation of mine by any means… this is called in OpenSSL the "envelope encryption", but for some reason it's only supported when using the C library and not when using the OpenSSL executable. This is also a common way for encryption in many applications because asymmetric encryption for data is impractical with the available tooling. I wrote this article because it seems that no one talks about this and everyone is busy typing possibly insecure passwords in their encryption archives. Hopefully this will become more common after this article.

Abandoning the server provider from 10-years: Stay away from myLoc/ServDiscount/Webtropia (review)

Introduction

It's a hot question what server providing service to use nowadays. The industry has boomed. The only thing that matters, though, is the reliability of a provider. With reliable I mean, the continuity of the service with no interruptions, the mutual understanding that problems can happen, and the urgency to correct problems to continue operation with minimal down-time. Ten years ago, myLoc was a good company. Nowadays, they're so cheap and bad I'm leaving them. I guess inflation didn't just inflate the currency.

Why write this in a blog post?

Because people on the internet have become so un-empathetic, robotic, and exhausting to talk to or discuss with, and my blog will minimize that because no one cares about my blog. Maybe it's a diary at this point. I can't remember in the last few years when I posted something on social media, and didn't get people licking the boot of corporations under the guise of "violating their terms" or whatever other dumb reason. As if common sense doesn't have any value anymore. Trust isn't of any value. I'm quite sure some genius out there will find a way to twist this story and make it entirely my fault, because humanity now evaluates moral decisions based on legality... what a joke we've become. Nowadays, you're not allowed to be angry. You can't be upset. You shouldn't be frustrated. You can't do mistakes. If you express any of your feelings towards an experience; your expression, regardless of how reasonable it's, will be called a rant and dismissed. So, I guess my blog is the best place to put this "rant", if you will. Who cares after all?!

I guess this will have a better chance to reach people than any robotic social media out there.

Story starts with bad internet connection

A few months ago I contacted ServDiscount (a subsidiary of myLoc, where my server is, IIUC) about constant internet connection problems (ticket 854255-700134-52). The internet connection problems started like a year ago, but recently got so bad (while my home's internet is around 1 Gbps). The problem was illustrated in many ways

  • File copying through sftp/ssh, was almost impossible. The speed throttles continuously and the download stops.
  • If I use any ssh tunnel, the terminal will not be usable anymore while the tunnel is doing any transfers, even small data was enough to block it
  • http(s) downloads of large files have become impossible; a simple attempt to download a file of 400 MB can't be accomplished.
  • Games with server software running on my server there could never be continued due to connection loss
  • ftps downloads constantly show "connection reset by peer", which I believe is the problem with everything else. The server-side connection was just resetting all the time.

As a patient and busy person, I didn't care. This went on for MONTHS. I'm not exaggerating. It was when this problem went out of control. Then, under the assumption that "it's my fault", I rented a specific VPS from ServDiscount, and guess what? Same problems. The VPS had NOTHING but a game server in it (plus iptables firewall with blocked input policy + open some ports), yet it was impossible to finish a game or two. People from all around the world would get disconnected after a while.

Bad support, all the way (starting October)

When I contacted support about this connection problem, the first blind response was "it's my fault". Because for this (bad) company, it can never be their fault. All their configuration is perfect. Everything they do is perfect. They can never do mistakes. That's what pissed me off. They couldn't explain the disconnects in the gaming server OR my original server. But of course, they claimed it might be a "botnet"... because why not? Since it's virtually impossible to deny the presence of botnet except with plausible deniability, they can never lose this argument. Yet with the presence of the second server, it was easy to prove that something is wrong there. It was easy to reproduce the problem, since an http download would fail. That was ready to view, test and debug. So, after that pressure, some guy in their support said "I'll take a look", and asked for access. I took the risk and created an account for them with sudoers power and added their public key, but they never logged in. It was easily observable in the logs, for weeks. Just empty promises with zero accountability.

After nagging them, they said "they're busy"... great support. As if I'm asking for a favor or something.

Then I got exhausted, and to appease them, I decided to wipe my server. I wish it were that easy.

Get your backups, if you can

Because of these internet issues, my backups were trapped on that server. I've tried to download them in many ways, but my backup's server software were constantly resetting the connection. Keep in mind that the software was used for years in the past. It's not like I invented these solutions recently or something. In fact, my only "invention", because of these problems, was to make these scripts run multiple times a day... just in an attempt to get the downloads to happen. For over a month, I couldn't download any backups. My backup logs were flooded with "connection reset by peer" errors. What the hell am I supposed to do now?

Well, I remained patient. It was a mistake. I should've probably escalated and gotten angry? But I don't think they would've done anything. When it's a bad company, it's a bad company.

Docker, as a tool to easily move away from bad situations

I didn't know too much about docker other than it's a containerization service that I barely used. In fact I used LXD more because it's modeled around preserving OSs, while docker is modeled around stateless preservation of data, where the software is renewed constantly, but the data is preserved.

The idea was simple: Instead of having to install all services on bare-metal and suffer when incompetent support treats me like this in migrations, I could just tar the containers with their data, move them somewhere else, and continue operation as if nothing happened. This way, I'll save time I don't really have, since I work now as a lead engineer and I can't really actively solve the same problems like I did back then when I was in academia. Sad fact of life: The older you grow, the less time you have.

So, I started learning docker. Watched tutorials, read articles, how-to, and many other things. I built images, did many things, and things were going fine. I containerized almost all my services. But one service was the cause of all evil...

Containerizing email services... big mistake and lots learned

The problem with containerization is that often you'll need a proxy to deliver your connections. You can setup your docker container to share the host's network, but I find that ugly and defeats the isolation picture of docker. My email server was proxied through haproxy.

Unfortunately, because of proxying, and because of my lack of understanding of how that worked (because I was learning), I misconfigured my email proxy and all the incoming connections to the email server were seen as "internal" connections because the source was the proxy software from within the server's network, which basically meant that all incoming email relay requests were accepted.

Our Nigerian friends and their prince were ready

Once that mistake was made, within a day, the server was being used as a relay for spam.

ServDiscount and their reaction

On 16.12.2022, because one email ended in a spam trap, the "UCEProtect" service flagged my server, and let's try to guess what ServDiscount/myLoc did:

  1. Contacted me, informing me of the issue and asking to correct it
  2. Switching the server to rescue mode, so that I can investigate the issue through the logs
  3. Completely block access to my server with no way for me to access the logs to understand the problem
  4. Refuse to unblock the server (even in rescue mode) unless UCEProtect gives the stamp of approval

Yep, it's 3 and 4.

It's completely understandable to block my server. After all, it was sending spam. No question there. But the annoying part is that I only knew about this whole thing by coincidence, when I attempted access to my server and couldn't. They only sent an email, which I didn't receive because my email server was blocked. They didn't attempt a phone-call, SMS or anything. They didn't even open a ticket IN MY ACCOUNT WITH THEM!

You might wonder whether it can get any more careless, passive and negligent from their end. Yes, it can!

Remember that I couldn't even download my backups because of their crappy internet connection, which they didn't diagnose or help fix. So I'm literally now trapped with no email access, my data is locked (for who knows how long), and... it gets worse.

I contacted their customer support. What do you think the answer was?

  1. We understand. Let us switch your server to rescue mode so that you can understand what happened
  2. Remove your server from UCEProtect's list (by paying them money) then come back

You guessed it. It's no. 2.

And again, remember, I can't even gain rescue access to my server. So until this point, I don't even have an idea what happened.

I go to UCEProtect, pay them around $100 (it was a Friday). Then went back to customer support. Guess their response:

  1. Thank you for removing your server from the list. Here's access back so that you can investigate the issue.
  2. We have zero communication with the "abuse department", so wait for them to react... fill the form they sent you to the email that you can't access.

You also guessed it. No. 2.

No amount of tickets, phone-calls, or begging helped. A robot would've understood better that I couldn't access my email so I have no way of responding.

Whether it's with bad policy or otherwise, they never help when you need help. They couldn't care less. So what if your server was stopped for days or even weeks based on UCEProtect listing? We don't care, and we won't help you fix the problem.

DNS change

While support was completely ignoring me, it occurred to me that I could switch my email MX DNS record to another service and receive my emails. Thanks to how MTAs (mail transfer agents) work, they don't give up so easily. On 17.12.2022, I got the email on another email provider, who I paid just to solve this problem, filled the form (without knowing why the issue happened, because again, how the hell will I know without access to my logs, even in rescue mode?!).

The holy abuse department is on the other side of the universe

So while I did everything they asked for. I filled the form, I removed my IP address from UCECrap, I didn't get my server until days later. Because the abuse department is simply unreachable. There's basically zero urgency to solve such a problem for a customer (who's been with them for 10 years). Who gives a flying f**k if your server and work halted for days?! Not myLoc, apparently.

Let's summarize

  • Bad internet connection with no help, so I couldn't even get my backups
  • No urgency to solve a problem I obviously didn't do deliberately, with zero value for being with them for 10 years
  • No access to server in rescue mode or VPN, yet I have to explain how the outbreak happened without logs, who knows how
  • Only contact through email, which was blocked, which they never addressed
  • Even after fulfilling their conditions, no one cares. No one helped, because the "abuse department" is on the other side of the universe.

What's the point of having a server with a company that treats its customers like that?

What's the point when accountability is too much to ask?

I don't know.

Conclusion

I'm not gonna sit here and claim that I'm perfect and none of this is my responsibility. But at least I expect common sense treatment for customers, urgency to help and reasonable way to access the server to see the logs, whether in rescue mode or VPN or whatever, and a reachable "abuse department" that doesn't hold all the keys with no accountability to customers. All this, and add that I've been with them for a decade.

But basically, the lesson here is, if anything goes wrong with your server in myLoc, you can go f**k yourself. No one will help you. You don't really matter to them. Unlike other companies that will simply put your server in rescue mode and ask you to fix the problem. MyLoc will simply block you. Maybe they're taking a cut out of UCEProtect? I don't know. But you can only wonder why a company will be that stupid. I'm out.

Have a great one.

A simple, lock-free object-pool

Introduction

Recently, I was using Apache Thrift for a distributed high performance C++ application. Apache Thrift is an RPC for calling functions on other ends of networks and across different languages. On a single thread, using an RPC is a bad idea, if performance is the goal. So the way to get high performance from such a system is by putting multiple clients in many threads. However, the problem is that Apache Thrift's clients are not thread-safe! What do we do?

The solution is an object pool of clients, and since the application is a high-performance, I chose it to be a lock-free object pool. Lock-free means that no mutexes are involved in the design, but only atomic variables. I couldn't find anything out there, so I implemented my own, which I hope will be useful to others, too. While this design is lock-free, it's not "wait-free". Meaning that, obviously, if all objects in the pool are used, the system will block/wait until an object is available, or the programmer has to setup an asynchronous waiting mechanism. It's possible to "try" to get an object in this design.

In the following I'll discuss my design of this object pool.

The design

The design of this object pool is simple.

  • There's a vector of size N that holds N initialized objects. The initialization of the objects is done in the constructor, by passing a functor/lambda that intializes every object and puts them in the vector (hence, the objects must be at least move-constructible).
  • I used a lock-free queue from boost. The queue has integers ranging from 0 to N-1. In order to check whether an object is available, its index in the vector has to be in this queue.
  • If borrowing is successful, a new object "BorrowedObject" will be returned, which contains a pointer to the borrows object. This is a safe mechanism, where returning to the pool is done automatically when this object is destroyed.

Shall we look at some code?

template <typename T>
class ObjectPool
{
    AvailableObjectsQueueType availableObjectsQueue;
    std::size_t               objectCount;
    std::vector<T>            objects;
    std::atomic_uint64_t      availableObjectsCount;
    std::atomic_bool          shutdownFlag;

public:
    friend BorrowedObject<T>;
    ObjectPool(std::size_t Size, std::function<T(std::size_t)> objectInitializers);
    ObjectPool()                  = delete;
    ObjectPool(const ObjectPool&) = delete;
    ObjectPool(ObjectPool&&)      = delete;
    ObjectPool& operator=(const ObjectPool&) = delete;
    ObjectPool& operator=(ObjectPool&&) = delete;

    BorrowedObject<T> borrowObj(uint64_t sleepTime_ms = 0);
    BorrowedObject<T> try_borrowObj(bool& success);
    std::size_t       size() const;
    uint64_t    getAvailableObjectsCount() const;
    std::vector<T>&   getInternalObjects_unsafe();
    void              shutdown();
    ~ObjectPool();
};

As you can see, the class is not copyable or movable, for simplicity. Besdies that, the following methods can be seen:

  • The constructor: Takes the size of the pool, and a functor/lambda to initialize the objects. The parameter in this functor/lambda is of type std::size_t. The purpose of this is to be able to have the initialization done as a function of the number of the object in the pool.
  • borrowObj(): A blocking method for borrowing an object from the pool.
  • try_borrowObj(): A non-blocking method for borrowing an object from a the pool, returns a null object on failure.
  • shutdown(): Shutdown the object pool, which calls the destructor of all objects and prevents borrowing further.

You can find the full implementation here.

Conclusion

Here's a simple design of a lock-free object pool. No more than 200 lines. The feature I find cool in this object pool is that the objects themselves are not being passed around, but only their indices, which can be done quite efficiently on most modern CPUs.

Safe resource allocation and deallocation in C++ (C++11 and C++03)

Introduction

Back then before 2010, one always used Valgrind to make sure that their C++ program isn't leaking memory. There's a whole modern way of using C++ that doesn't even make you need that. If you're using a C++11 program (and even if you're not), and you still require to keep checking whether your code is leaking memory, then you're most likely doing it all wrong. Keep reading if you wanna know the right way that saves you the trouble having to memory check all the time, and uses true object-oriented programming.

Basically this artice is about the concept named RAII, Resource Allocation Is Initialization, and why it's important from my perspective.

The golden rules of why you should do this

My Golden Rules in C++ development:

  1. Humans do mistakes, and just an arrogant would claim that he doesn't (why else do we have something called "error handling"?)
  2. Things can go wrong, no matter how robust your program is, and how careful you are, and you can't plan every possible outcome
  3. A problem-prone program is no better than a program with a problem; so why bother writing a program with problems?

Once you embrace these 3 rules, you'll never write bad code, because your code will be ready for worst case scenario.

In the last few years, I never found a single lost byte in my Valgrind-analysed programs; and I'm talking about big projects, not in the single class level. The difference will be clear soon.

I'm going to start from simple cases, up to more complicated scenarios.

Scenario 1: If you're creating and deleting objects under pointers

Consider the following example:

void DoSomethingElse(int* var)
{
    std::cout << *x << std::endl;
    //... do stuff with x
}
void DoSomething()
{
    int* x = new int;
    DoSomethingElse(x);
    delete x;
}

Let me make this as clear as possible: If you ever, ever use a new followed by delete... you're breaking all the 3 rules we made up there. Why? Here are the rules and how you're breaking them:

  1. You may do the mistake of forgetting to write that delete
  2. DoSomethingElse() might throw an exception, and hence that delete may not be called.
  3. This is a problem prone design, so it's a program with a problem.

The right way to do this: Smart pointers!

What are smart pointers?

I'm sure you've heard of them before, but if you haven't, the idea is very simple. If you define, for example, an integer like this:

void SomeFunction()
{
    int i = 0;
    // do stuff with i
} //here you're going out of the scope of the function

You never worry about deleting i. The reason is that once i goes out of scope, it's deleted automatically (through a destructor). Smart pointers are just the same. They wrap your pointer, such that they are deleted once they are out of scope. Let's look at our function DoSomething() again with smart pointers:

void DoSomething()
{
    std::unique_ptr<int> x(new int); //line 1
    DoSomethingElse(x.get());        //line 2
} //once gone out of scope, x will be deleted automatically, 
  //the destructor of unique_ptr will delete the integer

That's all the change you have to do, and you're done! In line 1, you're creating a unique_ptr, which will encapsulate your pointer. The reason why it's "unique" will become soon clear. Once the a unique_ptr goes out of scope, it'll delete the object under it. So you don't have to worry! This way, the 3 Golden Rules are served. In line 2, we're using x.get() instead of x, because the get() method will return the raw pointer stored inside the unique_ptr. If you'd like to delete the object manually, use the method x.reset(). The method reset() can take a parameter to another pointer, or can be empty to become nullptr.

PS: unique_ptr is C++11. If you're using C++03, you could use unique_ptr from the boost library

Why is it called "unique"?

Generally, multiple pointers can point to the same object. So, going back to the initial example, the following is a possible scenario:

void DoSomething()
{
    int* x = new int(1);
    int* y = x; //now x and y, both, point to the same integer
    std::cout << *x << "\t" << *y << std::endl; //both will print 1
    *x = *x + 1; //add 1 to the object under x
    std::cout << *x << "\t" << *y << std::endl; //both will print 2
    delete x; //you delete only 1 object, not 2!
}

But can you do this with unique_ptr? The answer is *no*! That's why it's called unique, because it's a pointer that holds complete *ownership* of the object under it (the integer, in our case), and it's unique in that. If you try to do this:

void DoSomething()
{
    std::unique_ptr<int> x(new int);
    std::unique_ptr<int> y = x; //compile error!
}  

your program won't compile! Think about it... if this were to compile, who should delete the pointer when the function ends, x or y? It's ambiguous and dangerous. In fact, this is exactly why auto_ptr was deprecated in C++11. It allowed the operation mentioned before, which effectively *moved* the object under it. This was dangerous and unclear semantically, which is why it's deprecated.

On the other hand, you can move an object from one unique_ptr to another! Here's how:

void DoSomething()
{
    std::unique_ptr<int> x(new int);
    std::unique_ptr<int> y = std::move(x);
    //now x is empty, and y has the integer, 
    //and y is responsible for deleting the integer
}

with std::move(x), you convert x to an rvalue reference, indicating that it can be safely moved/modified.

Shared pointers

Since we established that unique pointers are "unique", let's introduce the solution to the case where multiple smart pointers can point to the same object. The answer is: shared_ptr. Here's the same example:

void DoSomething()
{
    std::shared_ptr<int> x(new int(2)); //the value of *x is 2
    std::shared_ptr<int> y = x; //this is valid!
    //now both x and y point to the integer
}

Who is responsible for deleting the object now? x or y? Generally, any of them! The way shared pointers work is that they have a common reference counter. They count how many shared_ptrs point to the same object, and once the counter goes to zero (i.e., the last object goes out of scope), the last object is responsible for deleting.

In fact, using the new operator manually is highly discouraged. The alternative is use make_shared, which covers some corner cases of possible memory leaks. For example, if the constructor of the class use in shared_ptr has a multi-parameter constructor that may throw an exception. Here's how make_shared is used:

void DoSomething()
{
    std::shared_ptr<int> x = std::make_shared<int>(2); //the value of *x is 2
    std::shared_ptr<int> y = x; //this is valid!
    //now both x and y point to the integer
}

Note: Shared pointers change a fundamental aspect of C++, which is "ownership". When using shared pointers, it may be easy to lose track of the object. This is a common problem in asynchronous applications. This is a story for another day though.

Note 2: The reference counter of shared_ptr is thread-safe. You can pass it among threads with no problems. However, the thread-safety of the underlying object it points to is your responsibility.

Scenario 2: I don't have C++11 and I can't use boost

This is a common scenario in organizations that maintain very old software. The solution to this is very easy. Write your own smart pointer class. How hard can it be? Here's a simple quick-and-dirty example that works:

template <typename T>
class SmartPtr
{
    T* ptr;
    // disable copying by making assignment and copy-construction private
    SmartPtr(const SmartPtr& other) {} 
    SmartPtr& operator=(const SmartPtr& other) {return SmartPtr();}
public:
    SmartPtr(T* the_ptr = NULL)
    {
        ptr = NULL;
        reset(the_ptr);
    }
    ~SmartPtr()
    {
        reset();
    }
    void reset(T* the_ptr = NULL)
    {
        if(ptr != NULL)
        {
            delete ptr;
        }
        ptr = the_ptr;
    }
    T* get() const //get the pointer
    {
        return ptr;
    }
    T& operator*()
    {
        return *ptr;
    }
    T* release() //release ownership of the pointer
    {
        T* ptr_to_return = ptr;
        ptr = NULL;
        return ptr_to_return;
    }
};

and that's it! The method release(), I haven't explained. It simply releases the pointer without deleting it. So it's a way to tell the unique_ptr: "Give me the pointer, and forget about deleting it; I'll take care of that myself".

You can now use this class exactly like you use unique_ptr. Creating your own shared_ptr is a little more complicated though, and depends on your needs. Here's the questions you need to ask yourself on how to design this:

  1. Do you need multithreading support? shared_ptr supports thread-safe reference counting.
  2. Do you need to just count references, or also track them? For some cases, one might need to track all references with something like a vector of references or a map.
  3. Do you need to support release()? Releasing is not supported in shared_ptr, since it depends on reference counting, there's no way to tell other instances to release.

More requirements will require more work, especially that prior to C++11, multithreading was not in the C++ standard, meaning that you're gonna have to use system-specific C++.

For a strictly single-threaded application with C++03, I created a shared pointer implementation that supports releasing. Here's the source code.

Scenario 3: Enable a flag, do something, then disable it again

Consider the following code, which is common in GUI applications:

void GUIClass::addTheFiles(const std::vector<FileType>& files)
{
    this->disableButton();
    for(unsigned i = 0; i < files.size(); i++)
    {
        fileManager.addFile(files[i]);
    }
    this->enableButton();
}

While this looks legitimate way to do things, it's not. This is absolutely no different that the pointer situation. What if adding fails? Either because of a memory problem, or because of some exception? The function will exit without reenabling that button, and your program will become unusable and the user will probably have to restart it.

Solution? Just like before. Don't do it yourself, and get the destructor of some class to do it for you. Let's do this. What do we need? We need a class that will call a function with a reference to some variable on exit. Consider the following class:

class AutoHandle
{
    std::function<void()> func;
    bool done = false; //used to make sure the call is done only once
    // disable copying and moving
    AutoHandle(const AutoHandle& other) = delete;
    AutoHandle& operator=(const AutoHandle& other) = delete;
    AutoHandle(AutoHandle&& other) = delete;
    AutoHandle& operator=(AutoHandle&& other) = delete;
public:
    AutoHandle(const std::function<void()>& the_func)
    {
        func = the_func;
    }
    void doCall()
    {
        if(!done) 
        {
            func();
            done = true;
        }
    }
    ~AutoHandle()
    {
        doCall();
    }
};

Let's use it!

void GUIClass::addTheFiles(const std::vector<FileType>& files)
{
    this->disableButton();
    AutoHandle ah([this](){this->enableButton();}); //lambda function that contains the function to be called on exit
    for(unsigned i = 0; i < files.size(); i++)
    {
        fileManager.addFile(files[i]);
    }
} //Now, the function enableButton() will definitely be called definitely on exit.

This way, you guarantee that enableButton() will be called when the function exits. This whole thing here is C++11, but doing it in C++03 is not impossible, though I completely sympathize with you if you feel it's too much work for such a simple task, because:

  1. Since there's no std::function in C++03, we're gonna have to make that class template that accepts functors (function objects)
  2. Since there's no lambda functions in C++03, we're gonna have to make the call a new functor for every case (depending on how much you would like to toy with templates, also another big topic)

Just for completeness, here's how you could use AutoHandle in C++03 with a Functor:

template <typename CallFunctor, typename T>
class AutoHandle
{
    bool done; //used to make sure the call is done only once
    CallFunctor func;
    // disable copying by making assignment and copy-construction private
    AutoHandle(const AutoHandle& other) {}
    AutoHandle& operator=(const AutoHandle& other) {return *this;}
public:
    AutoHandle(T* caller) : func(CallFunctor(caller))
    {
        done = false;
    }
    void doCall()
    {
        if(!done)
        {
            func();
            done = true;
        }
    }
    ~AutoHandle()
    {
        doCall();
    }
};

struct DoEnableButtonFunctor
{
    GUIClass* this_ptr;
    DoEnableButtonFunctor(GUIClass* thisPtr)
    {
        this_ptr = thisPtr;
    }
    void operator()()
    {
        this_ptr->enableButton();
    }
};

Here's how you can use this:

void GUIClass::addTheFiles(const std::vector<FileType>& files)
{
    this->disableButton();
    AutoHandle<DoEnableButtonFunctor,GUIClass> ah(this); //functor will be called on exit
    for(unsigned i = 0; i < files.size(); i++)
    {
        fileManager.addFile(files[i]);
    }
} //Now, the function enableButton() will definitely be called definitely on exit.

Again, writing a functor for every case is a little painful, but depending on the specific case, you may decide. However, in C++11 projects, there's no excuse. You can easily make your code way more reliable with lambdas.

Remember, you're not bound to the destructor to do the calls. You can also call doCall() yourself anywhere (equivalent to reset() in unique_ptr). But the destructor will *guarantee* that the worst case scenario is covered if something went wrong.

Scenario 4: Opening and closing resources

This could even be more dangerous than the previous cases. Consider the following:

void ReadData()
{
    int handle = OpenSerialPort("COM3");
    ReadData(handle);
    Close(handle);
}

This form is quite common in old libraries. I faced such a format with the HDF5 library. If you read the previous sections, you'll get the problem with such usage and the idea on how to fix it. It's all the same. You *should never* close resources manually. For my HDF5 problem, I wrote a SmartHandle class that guarantees that HDF5 resources are correctly closed. Find it here. Of course, the formal right way to do this is to write a whole wrapper for the library. This may be an over-kill depending on your project constraints.

Notes on Valgrind

If you follow these rules, you'll be 100% safe with the resources you use. You rarely will ever need to use Valgrind. However, when you write the classes that we talked about (such as AutoHandle, SmartPtr, etc), it's very, very important not only to test it with Valgrind, but also to write good tests that will cover every corner case. Because once you do these classes right, you never have to worry about them. If you do them wrong, the consequences could be catastrophic. Surprising? Welcome to object-orient programming! This is exactly what "separation of concerns" mean.

Conclusion

Whenever you have to do, then undo something, then keep in mind that you shouldn't have this manually done. Sometimes it's safe and trivial, but many times it may lead to simply bad and error-prone design. I covered a few cases and different ways to tackle the issue. By following these examples, I guarantee that your code will become more compact (given that you're using C++11) and way more reliable.

Just a side-note on standards and rules

Sometimes when I discuss such issues related to modern designs, people claim that they have old code, and they don't want to change the style of the old code for consistency. Other times they claim that this would be violating some standard issued by some authority. All these reasons don't show that doing or not doing this is right or wrong. It just shows that someone doesn't want to do them because they're "following the rules". To me (and I can't emphasize enough that this is my opinion), it just is like asking someone "Why do you do this twice a day, how does it help you?", and get the answer "Because my religion tells me I have to do it". While I respect all ideologies, such an answer is not a rational answer that justifies the pros and cons of doing something. That answer doesn't tell why doing that twice a day helps that guy's health, physically or mentally or otherwise. He just is following a rule *that shouldn't be discussed*. I'm a rational person and I like discussing things by putting them on the table, which helps in achieving the best outcome. If someone's answer is "I have a standard I need to follow it", then that effectively and immediately closes the discussion. There's nothing else to add. Please note that I'm not encouraging breaking the rules here. If your superior tells you how to do it, and you couldn't convince them otherwise, then just do what he tells you, because most likely your superior has a broader picture of other aspects of a project that don't depend on code only.