Footguns

This section notes areas where certain usages can cause confusing bugs or problems.

Static Objects

If you maintain static variables which hold Botan objects, you will perhaps find that in some circumstances your application crashes in strange ways on shutdown. That is because, at least on some operating systems, Botan uses a locked memory pool as backing storage for the secure_vector type. This pool allocates out of pages which have been locked into memory using mlock or VirtualLock system calls.

If your variable happens to be destroyed before the pool, all is well. If the pool happens to be destroyed before the variable, then when the object goes to free its memory, a crash will occur.

This is basically the famous C++ “Static Initialization Order Fiasco”, except in reverse.

The best course of action is to avoid static variables. If that is impossible or inconvenient, one option is to disable the pool, either at build time (disable the locking_allocator module) or at runtime. Unfortunately the runtime setting requires setting an environment variable (see Environment Variables), and doing so consistently prior to static intialization is not trivial, due to the previously mentioned fiasco. One option might be to use GCC’s constructor function attribute.

Another approach is to use the utility class Allocator_Initializer (declared in mem_ops.h) as an associated static variable in your code. As long as the Allocator_Initializer is created before your static variables, that means the allocator is created before your object, and thus will be destroyed after your object is destroyed.

Ideally a more satisfactory solution to this issue could be found, especially given the difficulty of disabling the pool at runtime.

Multithreaded Access

It is perfectly safe to use the library from multiple threads.

It is not safe to use the same object from multiple threads, without some form of external serialization or locking.

There are a few exceptions to this rule, where the type itself maintains an internal mutexes. This will be noted in the respective documentation for that type.

Use of fork

If you use the fork syscall in your code, and attempt to use the library in both processes, likely bad things will happen due to internal locks. You can avoid this problem by either at build time disabling the features associated with these locks (namely locking_allocator and thread_utils) or disabling them at runtime using Environment Variables, ideally at the very start of main.