Don’t create reference from pointer (part 1/2)

When programming in C++ (or any other language) you can sometime hit very weird behavior. Like your “if” statements are ignored. You usually find this the hard way. Like when your program crashes. You check the debugger and you see, that it crashes on null pointer inside “if”. Yes the “if” that checks for null pointers. Strange.
Well in this post I will try to explain what is happening to your program.

In C++ we have something called a reference. Reference is basically an alias to some value/object. This alias has several key points defined in standard. Like a reference has to be bound to a valid object in declaration.

This binding in declaration has the effect that reference can not be null. You will basically always create a valid reference because it is an alias to something. This has some consequences in compilation and especially in resulting assembly.

In compilation compiler can detect when you are doing something wrong and warn you. In resulting assembly the optimizer can omit some checks because it knows, that the object is valid.

A little example

This post is going to explain you why checks are ignored, when using references. First, however lets see a little sample code without references. You will see that the binary doesn’t contain the “if” we put there.

Check this simple code:

int doSomething();

int main( int argc, char** argv )
{
    int i = 5;

    if( i == 5 )
    {
        doSomething();
    }

    return 0;
}

This is the assembly result when no optimization is applied.

main:
.LFB0:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $32, %rsp
        movl    %edi, -20(%rbp)
        movq    %rsi, -32(%rbp)
        movl    $5, -4(%rbp)
        cmpl    $5, -4(%rbp)
        jne     .L2
        call    _Z11doSomethingv
.L2:
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc

This is with -O3 passed to GCC compiler

main:
.LFB0:
        .cfi_startproc
        subq    $8, %rsp
        .cfi_def_cfa_offset 16
        call    _Z11doSomethingv
        xorl    %eax, %eax
        addq    $8, %rsp
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc

As you can see the compiled just completely ignored the “if” in the optimized build. Why? Because it knows, that the “if” will always evaluate to true.

This simple code and compiled assembly showed that compiler do some analysis based on what it knows. The same will apply to references. More on that in the second part of this article.

Building RPM – BuildRoot ignored

BuildRoot: %{_tmppath}/%{name}-%{version}-build

Will not be taken into account, because it is overwriten by .rpmrc or rpmbuild cmd line –buildroot
This behavior was introduced in rpm version 4.6.0 ( which was released 6th of January 2009 ). The BuildRoot should not be used any more, because to cite rpm mailing list:

Buildroot from spec is ignored on purpose in rpm 4.6.0. That specs should
(have to) define their own buildroot is simply bad design and a leftover
from ancient times.

The new default build root directory is simple:

$HOME/rpmbuild/BUILDROOT/%{name}-%{version}/

So this explains a lot. If you are like me and read all kind of rpm tutorials on the internet. Then wonder why the hell it does not work as expected.
It is pity that this little detail is not mentioned in some tutorials, created even after 2009.

Starting docker for the first time

I wanted to try an OpenSUSE Leap installation, just needed the shell not some GUI. My first choice in this kind of situation is to install a distro in VM. I was hearing a lot about docker and I said to myself, why not try a docker instead of VM.

First thing that came to my mind was – wait, can docker even run another linux distro? You know, docker images share kernel and I want to run another distro thus another kernel, this is job for virtualization.

I quickly discovered that you can run another linux distro in docker. Why? Well that’s easy. Every linux distro share the same kernel under the hood. Kernels ABI is usually pretty compatible across different versions.

I guess that all apps are just fine as long as they or better say their libs use syscalls that are available in the host kernel.

Now that we all know that docker can run linux distro let’s actually do that.

I’m running OpenSUSE Tumbleweed. It is a rolling-release distro so the steps may change a bit in future, but I think they will apply for at least some years to come.

Install docker:

sudo zypper install docker docker-compose

Add yourself to docker group so you can use it without sudo

sudo usermod -a -G docker your_name

Docker uses a dockerd daemon in the system, it should be running to use docker. Start it with systemctl

sudo systemctl start docker

To have docker auto start on boot enable it

sudo systemctl enable docker

You can check the whole config using

sudo systemctl status docker

● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2019-01-20 17:45:22 CET; 3h 41min ago
Docs: http://docs.docker.com
Main PID: 1343 (dockerd)
Tasks: 35
Memory: 401.7M
CGroup: /system.slice/docker.service
├─1343 /usr/bin/dockerd --add-runtime oci=/usr/sbin/docker-runc
└─1389 docker-containerd --config /var/run/docker/containerd/containerd.toml --log-level info

Search for the image you want

docker search opensuse

Download the image you want

docker pull opensuse/leap

This will download the latest version of that image, you can specify TAG, but let’s write about that in future post.

Check your installed images

docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
opensuse/leap latest bb77bd72ae3d 3 days ago 102MB

You can see the TAG here.

And now – run it

docker run -i -t opensuse/leap /bin/bash

You can check the params help later with
docker help run

Now you are in your new leap. You can look around, do stuff … . I was really curious about the ps aux command, you can try it too. It shows the compactness of containers.

Exit the image using CTRL+D or just type exit. You can now check the help for run or just check another command that list docker containers.

docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS               NAMES
3d3fd74d0748 opensuse/leap "/bin/bash" 2 hours ago Exited (0) About an hour ago kind_khorana

To attach to the container you have to first start it

docker start 3d3fd74d0748

Then attach to it

docker attach 3d3fd74d0748

After you are done with your container you can just delete it

docker rm 3d3fd74d0748

This will delete the container only, not the image. You can check both with commands before. You can run another container of the image anytime you want.

And that is it. So far docker seems very nice.
In another post I will try to run web server in my container so don’t forget to check it how it will turn out.