UPDATE: February 21st, 2014 — I happened across another solution to the same problem: pump.py. It also looks quite interesting, but may be intended for a narrower set of use cases…


I ran across the GSL project today and fell heavily in like.  I’m starting to get really interested in code generation as a master-level technique. All sorts of activities lend themselves to code generation, but the things I’m most interested in auto-generating at the moment are:

  • Unit and regression tests
  • Scripting language bindings
  • Message marshallers/demarshallers

GSL seems like it could be a great tool for all of this and more.  The czmq project provides some real-world examples of GSL in action, including auto-generation of CMake and Visual Studio project files. This utility is definitely something I plan to investigate—if I don’t drown in the deluge of boilerplate code and tests at work first. Sad smile

Another interesting thing I trolled from the iMatix github repos is gitdown, and (by proxy) ditaa.  Looks like a great way to leverage markdown on github pages to make truly useful and complete documentation right on a project’s front page. Nice…

{ 0 comments }

We have a lot of code at work that checks the return value of malloc() for NULL, but I’ve come across a fair number of posts claiming that this is pointless on most Linux systems because the return value of malloc() is very often a lie (due to overcommit being enabled). This article explains the details, and provides three example programs intended to demonstrate the effect. On my desktop system, they fail differently (as the article claims they should). Here’s the last thing printed by each program:

  • demo1: malloc failure after 3056 MiB
  • demo2: malloc failure after 1629 MiB
  • demo3: malloc failure after 3056 MiB (last loop value printed before being killed = 1629)

This was run in a virtual Ubuntu 13.04 instance for which cat /proc/meminfo prints:

% cat /proc/meminfo 
MemTotal:        1026284 kB
MemFree:          813032 kB
Buffers:            2300 kB
Cached:            49732 kB
SwapCached:        46672 kB
Active:            15532 kB
Inactive:         122972 kB
Active(anon):      14856 kB
Inactive(anon):    74396 kB
Active(file):        676 kB
Inactive(file):    48576 kB
Unevictable:           0 kB
Mlocked:               0 kB
HighTotal:        135048 kB
HighFree:           1764 kB
LowTotal:         891236 kB
LowFree:          811268 kB
SwapTotal:       1046524 kB
SwapFree:         833304 kB
Dirty:                12 kB
Writeback:             0 kB
AnonPages:         54552 kB
Mapped:            17424 kB
Shmem:              2600 kB
Slab:              31004 kB
SReclaimable:      12984 kB
SUnreclaim:        18020 kB
KernelStack:        3216 kB
PageTables:         6332 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     1559664 kB
Committed_AS:    1874248 kB
VmallocTotal:     122880 kB
VmallocUsed:       23508 kB
VmallocChunk:      97920 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:       30712 kB
DirectMap2M:      882688 kB

Also note that overcommit is set to zero:

% cat /proc/sys/vm/overcommit_memory 
0

There are conflicting reports about what this actually means, but I’m going to trust the article containing the demo programs, which claims that zero means: “guess about how much overcommitment is reasonable”, i.e., it implies that overcomit is enabled.

The article also states: “On a well-functioning system, like Solaris, the three demo programs obtain the same amount of memory and do not crash but see malloc() return NULL.” Okay, so now I have a dilemma. Am I to take this as proof that you can’t trust the return value of malloc()? How, then, should one deal with memory allocation failures? Is it reasonable to take the glib approach of terminating the application? And how does swap being enabled (or not) affect the situation?

The latter question is answerable. If I run:

sudo swapoff --all

and re-run the demo programs, the results are:

  • demo1: malloc failure after 3055 MiB
  • demo2: malloc failure after 610 MiB
  • demo3: malloc failure after 3055 MiB (last loop value printed before being killed = 610)

Interestingly: the second time—and all subsequent times—I tried to run either demo2 or demo3 with swap disabled, it killed my X session, just as the article suggested it might. It seems it was sort of a fluke that I was able to run it at all. (I’m guessing X allocates a lot of memory on startup that it later frees, so I was just lucky to have run the demos on a ‘quiescent’ system the first time.)

Should I conclude from this that it’s not actually possible to detect memory allocation failures in a robust way on desktop Linux systems? It would appear so. The third demo program never sees a malloc() failure, but it invokes the OOM killer nonetheless.  I’ve come across hints/anecdotes suggesting that there are other failure modes for malloc() that could return NULL instead of invoking the OOM killer (like if the virtual memory system becomes fragmented and can’t find a chunk of the requested size), but the bottom line seems to be: it is generally not possible to detect all memory allocation failures in Linux applications.  This makes the glib approach seem like it’s not too unreasonable—for desktop apps, at least.

Which brings me to embedded Linux. Is the situation with respect to memory allocation failures the same there? To find out, I ran the same demo programs on an i.MX6-based board (similar to the SABRE Lite) . Here are some details on the device:

# cat /proc/sys/vm/overcommit_memory 
0
# cat /proc/meminfo 
MemTotal:        1940720 kB
MemFree:         1856396 kB
Buffers:            6504 kB
Cached:            40496 kB
SwapCached:            0 kB
Active:            16580 kB
Inactive:          38584 kB
Active(anon):       8160 kB
Inactive(anon):       16 kB
Active(file):       8420 kB
Inactive(file):    38568 kB
Unevictable:           0 kB
Mlocked:               0 kB
HighTotal:        434176 kB
HighFree:         384204 kB
LowTotal:        1506544 kB
LowFree:         1472192 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Dirty:                32 kB
Writeback:             0 kB
AnonPages:          8152 kB
Mapped:            11360 kB
Shmem:                24 kB
Slab:              11564 kB
SReclaimable:       5644 kB
SUnreclaim:         5920 kB
KernelStack:         896 kB
PageTables:         1056 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:      970360 kB
Committed_AS:      40160 kB
VmallocTotal:     196608 kB
VmallocUsed:        1908 kB
VmallocChunk:     191652 kB

Note that swap is disabled. Here are typical results of running the demo programs on this ARM system:

  • demo1: malloc failure after 1580 MiB
  • demo2: malloc failure after 1593 MiB
  • demo3: malloc failure after 1577 MiB  (last loop value printed before being killed = 1577)

The numbers printed in each run differ slightly, but they’re the same within a few tenths of a percent or so. What’s very consistent is the fact that demo3 is always killed at the point where the loop index matches the amount of memory at which malloc() failed. Thus, it appears that  our ARM development board is what the article’s author refers to as “a well-functioning system, like Solaris”.

Can I bank on malloc() always returning NULL on this ARM system? And if so, what, specifically, is it that makes this possible? Think I feel an SO post coming on…

UPDATE1: Posted this question to stackoverflow.com. No answers yet…

UPDATE2: For a goof, I tried running the demo programs in single user mode (implies swap=off) on my Linux VM to see whether this made a difference.  It did not. The results were:

  • demo1: malloc failure after 3056 MiB
  • demo2: malloc failure after 883 MiB
  • demo3: malloc failure after 3056 MiB (last loop value printed before being killed = 892)

This article helped me figure out how to coax my VMWare-based Ubuntu 13.04 instance into single user mode. Here’s a cheat sheet:

  1. Press and hold SHIFT while (re)booting until the GNU GRUB menu comes up
  2. Select Advanced Options for Ubuntu
  3. Select the (recovery mode) version of the latest kernel, e.g., something like: Ubuntu, with Linux 3.8.0-33-generic (recovery mode)
  4. After the recovery kernel boots, select Drop to root shell prompt
  5. Remount the root filesystem in read/write mode by typing: mount –o remount,rw /

So, bottom-line: the behavior with respect to malloc() did not change when I ran the demo programs as user root on a relatively ‘unloaded’ system—an environment that’s a bit more similar to our ARM target’s. The desktop system is still a big fat liar when it comes to the return value of malloc(). Why is the target (seemingly) better behaved?

{ 0 comments }

Static analysis with clang/scan-build

November 6, 2013

My buddy Jim-James asked me how to get CMake to use clang today, and we wound up figuring out that this works: cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .. Well, it works if you do this first: sudo apt-get install clang Anyway,  the cool thing is, clang’s diagnostic output is much more verbose/helpful than gcc’s. I knew this […]

Read the full article →

Close a Hung SSH Session

October 28, 2013

After 15 years of having to deal with this problem once in a blue moon, I finally got annoyed enough to look up the solution. Just hit ENTER + ~ + . to get out of a hung SSH session. (That’s ENTER, followed by a tilde, followed by a period.)  Kinda handy when you’re debugging […]

Read the full article →

APSW May be Your New Best Friend

September 29, 2013

Someday. Keep this link around. The VFS and virtual table support are intriguing, if nothing else. And (Note To Self), when people talk about pysqlite, they’re (apparently) talking about what you get when you type import sqlite3 in Python.  Oh, and the first link says “APSW always handles Unicode correctly.” Good to know.

Read the full article →

Windows Live Writer

August 29, 2013

Okay, confession time: I freakin’ love Windows Live Writer. I know, I know, there goes my Linux-/Mac-guy street cred, but… it’s pluggable/extensible and it ‘just works’. Well, it did, anyway, until I upgraded to WLW 2012 and started getting SSL errors.  This post helped me figure out that creating a shortcut to WLW that passes […]

Read the full article →

YASSL

June 19, 2013

Hello again, Self! That’s: Yet Another Signals and Slots Library (not its real name). Happened across this and it looks pretty interesting: – https://github.com/pbhogan/Signals Give it a look next time as an alternative to sigslot.h.

Read the full article →

Booting a Custom Yocto Image on i.MX6 SABRE Lite

June 18, 2013

Well, I guess they call it a BD-SL-i.MX6 now, for whatever reason. Anyway, I ordered one of them last year on September 17th in the hopes that it would prove useful at work, but my employer changed directions and I didn’t get to play with it much. I did try to spin up some Yocto-built […]

Read the full article →

Code Completion in Vim, Jerry Maguire-Style

June 13, 2013

Awful name, interesting project: https://github.com/Valloric/YouCompleteMe. An acquaintance of mine says this actually works quite well with C++ code. I’ll have to give a try sometime…

Read the full article →

Nice zsh Presentation

June 5, 2013

Okay, already, I’ll get with the program! – http://www.slideshare.net/jaguardesignstudio/why-zsh-is-cooler-than-your-shell-16194692 Coolest tips: Global and suffix aliases Recursive globbing, e.g., ls **/*.log Environment variable editing, e.g.,vared PATH Programmable renaming, e.g., zmv ‘(*).html’ ‘$1.txt’ (requires autoload zmv first if it’s not already loaded)

Read the full article →