Memory limits, soft or hard, appear to have no effect on programs running under Linux emulation, allowing them to allocate memory until the machine runs out of virtual memory. How-To-Repeat: Set a low memory limit. Soft or hard, it doesn't matter: $ ulimit -H -m 8192 Run a linux program which likes to allocate lots of memory, and watch it grow, and grow, and grow. I discovered this using acroread 4.05, which has a marvelous memory leak - when the display covers most of the screen, it grows by several MB each time you move to a different page. I had it grow to over 100 MB with a memory limit of just 8 MB.
On Mon, 13 Nov 2000 hanche@math.ntnu.no wrote: > >Description: > Memory limits, soft or hard, appear to have no effect on programs > running under Linux emulation, allowing them to allocate memory until > the machine runs out of virtual memory. > >How-To-Repeat: > Set a low memory limit. Soft or hard, it doesn't matter: > $ ulimit -H -m 8192 I think you want to use -d (data segment size) and maybe -s (stack size) instead of -m (max memory size) (better described as max resident set in setrlimit(2)). -m limits use of real memory but doesn't limit use of virtual memory. > Run a linux program which likes to allocate lots of memory, > and watch it grow, and grow, and grow. > I discovered this using acroread 4.05, which has > a marvelous memory leak - when the display covers most of the screen, > it grows by several MB each time you move to a different page. > I had it grow to over 100 MB with a memory limit of just 8 MB. Marvelous indeed. It has (effectively) hung my system a couple of times with earlier versions of acroread4. Bruce
+ Bruce Evans <bde@zeta.org.au>: | On Mon, 13 Nov 2000 hanche@math.ntnu.no wrote: | | > Set a low memory limit. Soft or hard, it doesn't matter: | > $ ulimit -H -m 8192 | | I think you want to use -d (data segment size) and maybe -s (stack | size) instead of -m (max memory size) (better described as max | resident set in setrlimit(2)). -m limits use of real memory but | doesn't limit use of virtual memory. Oh, I didn't know that. (In fact, it's a bit tricky to correlate the limits described in setrlimit(1) with those handled by the (u)limit command in various shells. More to the point, however, in my experiment I used both -d and -s as well as -m, and still the process grew without bound. I'm sorry, I should have mentioned that. - Harald
On Tue, 14 Nov 2000, Harald Hanche-Olsen wrote: > More to the point, however, in my experiment I used both -d and -s as > well as -m, and still the process grew without bound. I'm sorry, I > should have mentioned that. mmap() ignores all of the limits even for native processes, so the limits are no use for limiting buggy or malicious programs that use mmap(). vm has surprisingly few references to the limits. Most are just to set the defaults. The others are: - limit on normal stack growth in vm_map.c should work. I think programs can still build abnormally large stacks using mmap(). - limit on locked memory in vm_mmap.c should work. - limit on rss in vm_pageout.c should work. It is only used when the system becomes short of memory. - limit on data size in vm_unix.c works, but only affects the break(2). This limits malloc(3). The data limit also affects loading of programs, but there are problems there too. It has no effect for elf programs. Bruce
Responsible Changed From-To: freebsd-bugs->marcel My plate.
The reason Linux binaries don't respect the limits is as follows: In glibc2 allocations larger than a threshold (128K) use mmap(). Below the threshold brk() is used. Since our native mmap doesn't respect the limits, Linux binaries won't always fail when allocating more than the limit. The following program has been used to verify this. \begin{mem.c} #include <ctype.h> #include <limits.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { size_t blksize, blkcount, memsize; char *ptr, *suffix; if (argc != 2) errx(1, "add size of allocated memory"); memsize = strtoul(argv[1], &suffix, 0); if (suffix == argv[1]) errx(1, "invalid memory size"); switch (toupper(*suffix)) { case '\0': break; case 'K': memsize *= 1024; break; case 'M': memsize *= 1024 * 1024; break; default: errx(1, "invalid suffix"); } blksize = 64*1024; blkcount = 0; #ifdef SINGLE_ALLOC ptr = malloc(memsize); if (ptr == NULL) errx(1, "malloc failed"); #else while (memsize) { blkcount++; ptr = malloc(blksize); if (ptr == NULL) errx(1, "malloc failed: block %d; %d remaining", blkcount, memsize); memsize -= blksize; } #endif return 0; } \end{mem.c} If compiled with -DSINGLE_ALLOC, the linux version (linuxmem) will succeed where the FreeBSD version (bsdmem) will fail: % limit datasize 16M % ./bsdmem 17M bsdmem: malloc failed % ./linuxmem 17M % If the allocation size is reduced to below the mmap() threshold, both versions will fail as expected: % limit datasize 16M % ./bsdmem 17M bsdmem: malloc failed: block 256; 1114112 remaining % ./linuxmem 17M linuxmem: malloc failed: block 256; 1114112 remaining % The bug therefore is in our native mmap() syscall and not in the Linuxulator. I'll see if I can fix our mmap, although I'm no VM guy. If I don't manage (likely, but you'll never know until you try), I'll either file a new PR or bug someone who should be able to fix it. FYI, -- Marcel Moolenaar mail: marcel@cup.hp.com / marcel@FreeBSD.org tel: (408) 447-4222
Responsible Changed From-To: marcel->emulation Assign to emulation@FreeBSD.org. It is not going to be addressed if it's assigned to me and I don't do it. Maintainership of the Linuxulator has been passed on to emulation@FreeBSD.org as well.
The "bug" here is that mmap does not respect the datasize limit (ulimit -d). But this may actually be correct. mmap'ed space is in some sense not part of the "data segment"; at least, it is not necessarily contiguous with the main data segment. I tested Linux and Solaris, and neither one subjects mmap to the datasize limit. The Linux malloc is a little counter-intuitive in that it may use mmap to acquire its memory, thus placing it outside the data segment and beyond the purview of ulimit -d, but I'm not sure I would call this a bug. mmap is subject to the virtual memory limit (ulimit -v) on FreeBSD, as it is on Linux and Solaris as well. So this is probably the right limit to set if you want to restrict how much memory the process can use. Maintainers, consider closing this? -- Nate Eldredge nge@cs.hmc.edu
As the originator of this PR, I guess I should chime in, though this is a bit outside my expertise. Nate's explanation seems reasonable to me, so I think it is indeed time to close this one. (And the problem doesn't bite me anymore, anyway.) - Harald
State Changed From-To: open->closed Closed at submitter's request.