System V Shared Memory Reading /proc/PID/maps β€” Shared Memory in the Virtual Address Space

 

System V Shared Memory
Reading /proc/PID/maps β€” Shared Memory in the Virtual Address Space
πŸ“‚ Section 48.5
πŸ—ΊοΈ /proc/PID/maps
🎯 Interview Ready

What is /proc/PID/maps?

Every Linux process has its own virtual address space. This space is divided into segments β€” executable code, data, stack, shared libraries, memory mappings, and shared memory. The kernel exposes a complete view of this layout through a special file: /proc/PID/maps, where PID is the process ID.

For System V shared memory, this file is extremely useful. You can see exactly where a segment is attached in virtual memory, what permissions it has, and whether it has been marked for deletion. Understanding this file is fundamental to debugging IPC issues.

Key Terms in This Topic

/proc/PID/maps virtual address space SYSV tag IPC_PRIVATE MAP_SHARED MAP_PRIVATE tmpfs vdso shmat() memory segment

The Six Columns of /proc/PID/maps

Each line in the file represents one memory segment. There are exactly six columns on every line.

# Column Name Example Meaning
1 Address range b7e40000-b7e41000 Start and end virtual addresses in hex. The end address is the first byte after the segment.
2 Permissions rw-s r=read, w=write, x=execute, hyphen=disabled. Last char: p=private (copy-on-write), s=shared. System V shm is always ‘s’.
3 Offset 00000000 Byte offset into the backing file. For System V shm this is always 0.
4 Device 00:06 Major:minor device number of the backing file’s device.
5 Inode / shmid 1577924 For regular files: inode number. For System V shm: the shmid (integer returned by shmget()).
6 Name / Tag SYSV00000000 (deleted) For System V shm: “SYSV” + shmget() key in hex. “(deleted)” is normal β€” see explanation below.

Annotated /proc/PID/maps Output for a Shared Memory Process

When a process attaches two System V shared memory segments and uses standard libraries, the maps file looks like this. Each group of lines is explained below.


/* /proc/12345/maps β€” annotated */

08048000-0804c000  r-xp  00000000  08:01  456789  /home/user/shm_attach  /* q: text segment */
0804c000-0804d000  rw-p  00003000  08:01  456789  /home/user/shm_attach  /* q: data segment */
0804d000-0804e000  r--p  00004000  08:01  456789  /home/user/shm_attach  /* q: string constants (read-only) */

b7e00000-b7e10000  rw-s  00000000  00:06  3       SYSV00000000 (deleted) /* w: shm segment 1 */
b7e10000-b7e20000  rw-s  00000000  00:06  4       SYSV00000000 (deleted) /* w: shm segment 2 */

b7e20000-b7f60000  r-xp  00000000  08:01  1234    /lib/libc-2.17.so      /* e: C library text */
b7f60000-b7f62000  rw-p  00140000  08:01  1234    /lib/libc-2.17.so      /* e: C library data */

b7f70000-b7f90000  r-xp  00000000  08:01  5678    /lib/ld-2.17.so        /* r: dynamic linker */
b7f90000-b7f91000  rw-p  0001f000  08:01  5678    /lib/ld-2.17.so

bffdf000-c0000000  rw-p  00000000  00:00  0       [stack]                /* t: process stack */
ffffe000-fffff000  r-xp  00000000  00:00  0       [vdso]                 /* y: virtual DSO */
    

q β€” Main program (3 lines)

Text segment (r-xp): executable code.
Data segment (rw-p): global/static variables.
Read-only page (r–p): string literals baked into the binary.

w β€” System V Shared Memory (2 lines)

Permissions show rw-s β€” the ‘s’ flag means shared mapping.
Column 5 = shmid (3 and 4 here).
Tag: SYSV + key in hex + “(deleted)”.

e & r β€” Shared Libraries

libc (standard C library) mapped in.
ld (dynamic linker) mapped in.
Private (‘p’) mappings β€” copy-on-write on write.

t & y β€” Stack and vDSO

[stack]: grows downward toward lower addresses.
[vdso]: virtual dynamic shared object. Added since kernel 2.6.12. Used for fast user-space syscalls.

Decoding the Permission String

The permission field is always 4 characters, e.g. rw-s or r-xp.

r
Read. Process can read memory in this segment.
w
Write. Process can write to this segment.
x
Execute. CPU can run instructions in this segment.
Permission disabled. Replaces r, w, or x.
p
Private (copy-on-write). Changes not visible to others.
s
Shared. All processes see each other’s writes. Always ‘s’ for System V shm.

Why “SYSV00000000 (deleted)”? β€” Explained Simply

The tag for a System V shared memory segment has two parts:

SYSV00000000

“SYSV” is a fixed prefix the kernel always adds.

The hex number after it is the key that was passed to shmget(). When you use IPC_PRIVATE (value = 0), the hex digits are all zeros. If you used a key like 0xABCD1234, the tag would show SYSVabcd1234.

(deleted)

This is not an error and does not mean the segment is broken.

The kernel internally backs System V shared memory with a file in a hidden tmpfs filesystem (RAM-based). It immediately unlinks (deletes) the directory entry after creating it β€” exactly like the pattern of opening a file and calling unlink() before using it. The data still lives in RAM; only the name is gone. Hence “(deleted)”.


/* How the kernel implements System V shm internally (simplified concept) */

/* Step 1: create a file in a hidden tmpfs (RAM filesystem) */
int fd = open("/dev/shm/.internal_shm_XXXX", O_RDWR | O_CREAT, 0600);

/* Step 2: immediately unlink β€” removes the name, data stays in RAM */
unlink("/dev/shm/.internal_shm_XXXX");

/* Step 3: shmat() mmap()-maps this anonymous fd into the process VA space */
void *addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

/* Result in /proc/PID/maps:
   b7e40000-b7e41000  rw-s  00000000  00:06  3  SYSV00000000 (deleted)
   The "(deleted)" is because the tmpfs name was unlinked in step 2.       */
    

Code: Read /proc/self/maps and Find Shared Memory Entries

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/shm.h>

#define SHM_SIZE 4096

int main(void)
{
    int   shmid;
    char *addr;
    FILE *fp;
    char  line[512];

    /* Create a shared memory segment using IPC_PRIVATE */
    shmid = shmget(IPC_PRIVATE, SHM_SIZE, IPC_CREAT | 0660);
    if (shmid == -1) { perror("shmget"); exit(EXIT_FAILURE); }

    /* Attach β€” kernel chooses the virtual address */
    addr = shmat(shmid, NULL, 0);
    if (addr == (void *)-1) { perror("shmat"); exit(EXIT_FAILURE); }

    printf("Shared memory attached at: %p  (shmid=%d)\n\n", addr, shmid);

    /* Open /proc/self/maps β€” this is our own process's map */
    fp = fopen("/proc/self/maps", "r");
    if (!fp) { perror("fopen"); exit(EXIT_FAILURE); }

    printf("=== Lines containing 'SYSV' in /proc/self/maps ===\n");
    while (fgets(line, sizeof(line), fp) != NULL) {
        if (strstr(line, "SYSV"))
            printf("  %s", line);
    }
    fclose(fp);

    shmctl(shmid, IPC_RMID, NULL);
    shmdt(addr);
    return 0;
}
/*
 * Compile: gcc -o maps_demo maps_demo.c
 * Run:     ./maps_demo
 *
 * Sample output:
 * Shared memory attached at: 0xb7e40000  (shmid=3)
 *
 * === Lines containing 'SYSV' in /proc/self/maps ===
 *   b7e40000-b7e41000 rw-s 00000000 00:06 3  SYSV00000000 (deleted)
 */
    

Code: Two Segments β€” Labelled Memory Map Dump

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/shm.h>

int main(void)
{
    int   id1, id2;
    char *a1, *a2;
    FILE *fp;
    char  line[512];

    id1 = shmget(IPC_PRIVATE, 4096, IPC_CREAT | 0660);
    id2 = shmget(IPC_PRIVATE, 8192, IPC_CREAT | 0660);
    a1  = shmat(id1, NULL, 0);
    a2  = shmat(id2, NULL, 0);

    printf("Segment 1: shmid=%-4d  addr=%p  size=4096\n", id1, a1);
    printf("Segment 2: shmid=%-4d  addr=%p  size=8192\n\n", id2, a2);

    fp = fopen("/proc/self/maps", "r");
    printf("%-40s %-6s  Type\n", "Address Range", "Perms");
    printf("%-40s %-6s  ----\n", "-------------", "-----");

    while (fgets(line, sizeof(line), fp) != NULL) {
        char range[40], perms[8], off[12], dev[8], ino[16], name[256];
        name[0] = '\0';
        sscanf(line, "%39s %7s %11s %7s %15s %255[^\n]",
               range, perms, off, dev, ino, name);

        const char *type =
            strstr(name, "SYSV")    ? "*** SHM SEGMENT ***" :
            strstr(name, ".so")     ? "shared library"      :
            strstr(name, "[stack]") ? "stack"               :
            strstr(name, "[vdso]")  ? "vdso"                :
            strlen(name) > 0        ? "file mapping"        :
                                      "anonymous";

        printf("%-40s %-6s  %s\n", range, perms, type);
    }
    fclose(fp);

    shmctl(id1, IPC_RMID, NULL);
    shmctl(id2, IPC_RMID, NULL);
    shmdt(a1);
    shmdt(a2);
    return 0;
}
    

What is the [vdso] Entry?

[vdso] stands for Virtual Dynamic Shared Object. The kernel maps a tiny shared library into every process automatically. Its purpose is to make certain very-frequent system calls faster by running them partly in user space, avoiding the full user-to-kernel context switch overhead.

Why it exists

Calls like gettimeofday() and clock_gettime() are called millions of times per second in some programs. A normal syscall requires a ring-3 to ring-0 transition. The vDSO lets these calls read kernel-maintained data (like the current time) directly from user space β€” no context switch needed.

When it appears

The [vdso] entry appears only in kernels since version 2.6.12. On older kernels a different mechanism called [vsyscall] was used at a fixed address. The vDSO is mapped at a random address each time (ASLR-aware).

Interview Questions β€” /proc/PID/maps and Shared Memory

Q1: What is /proc/PID/maps and why is it useful for shared memory debugging?

Answer: It is a virtual file exposed by the Linux kernel that shows the complete virtual address space layout of process PID β€” every segment on one line each. For shared memory debugging it lets you confirm that a segment was attached, see what address it landed at, verify permissions, read the shmid from column 5, and check whether it has been marked for deletion.

Q2: How do you distinguish a System V shared memory segment from a regular file mapping in /proc/PID/maps?

Answer: By column 6 (the name/tag). A System V shm segment shows SYSV followed by the key in hex, e.g. SYSV00000000 (deleted). A regular file mapping shows a full filesystem path. Additionally, shm is always flagged s (shared) in the permissions; regular private file maps use p.

Q3: Why does a System V shared memory segment appear as “(deleted)” even though it is in use?

Answer: The kernel implements System V shm by creating a file in a hidden tmpfs RAM filesystem, then immediately unlinking its directory entry. The data stays in RAM as long as any process maps it β€” only the name is gone. This is the same open-then-unlink pattern used to create anonymous temporary files. The “(deleted)” label is a normal implementation artifact, not an error.

Q4: A segment is created with IPC_PRIVATE key. What tag appears in /proc/PID/maps?

Answer: SYSV00000000 (deleted). The zeros appear because IPC_PRIVATE has the numeric value 0. The format is always “SYSV” + key in hex. If you had used key 0xDEADBEEF, you would see SYSVdeadbeef (deleted).

Q5: What is the difference between the ‘p’ and ‘s’ flags in the permissions column?

Answer: p = private (copy-on-write). The process gets its own copy of the page if it writes β€” changes not visible to others. s = shared. All processes sharing this mapping see each other’s writes in real time. System V shared memory is always s β€” sharing data is the entire purpose.

Q6: What does column 5 represent for a System V shared memory segment?

Answer: For normal file mappings column 5 is the inode number of the file. For System V shm it holds the shmid β€” the integer identifier returned by shmget(). You can use this to cross-reference with ipcs -m which lists all segments by shmid.

Q7: Two processes attach the same segment. Will it appear at the same address in both /proc/PID/maps files?

Answer: Not necessarily. When shmat(shmid, NULL, 0) is called β€” NULL means “let the kernel choose” β€” the kernel picks a free region independently for each process. Both will show the same shmid in column 5 and the same SYSV tag, but the address range in column 1 may differ. This is exactly why storing absolute pointers inside shared memory is wrong β€” you must use relative offsets instead.

Next: Why Absolute Pointers in Shared Memory Are Dangerous

Learn the correct offset-based technique for building linked lists and trees inside shared memory.

β†’ Storing Pointers in Shared Memory EmbeddedPathashala Home

Leave a Reply

Your email address will not be published. Required fields are marked *