A process that crashes without leaving a core file behind isn’t necessarily a debugging mystery: on most modern distributions, ulimit -c (the maximum allowed size for a core dump) defaults to 0, silently disabling core dump generation entirely, with no error message at crash time.

What ulimit -c actually controls

ulimit -c sets the maximum size, in blocks, a core dump is allowed to reach. A value of 0 doesn’t limit the size, it flatly forbids writing the file: the process crashes normally, the signal (SIGSEGV, for instance) does its job, but no trace is left for post-mortem analysis.

# Current value for the active shell session
ulimit -c
# 0

# Allows unlimited-size core dumps
# for the current shell session only
ulimit -c unlimited

The trap: this setting doesn’t survive the shell session

ulimit -c unlimited applied in a terminal changes nothing for a service that’s already running, nor for a process launched through any path other than that specific shell: the limit applies to the current shell and anything it launches afterward, never retroactively, never globally.

The same systemd trap encountered elsewhere

A systemd-managed service ignores /etc/security/limits.conf for its own limits, exactly like the file descriptor limits already documented: a service’s core dump limit must be set directly in its unit file, not in the traditional PAM configuration that only applies to login sessions.

# In the service unit file (or an override
# via systemctl edit), not in limits.conf
[Service]
LimitCORE=infinity

core_pattern: the second setting people forget

Even with ulimit -c unlimited correctly set, no file shows up if /proc/sys/kernel/core_pattern points to an external handler (like systemd-coredump on most modern distributions) without checking where it actually stores dumps: the core dump does exist, just not necessarily where habit makes people look (./core in the process’s working directory).

# On a distro with systemd-coredump,
# core dumps are managed and stored elsewhere
cat /proc/sys/kernel/core_pattern
# |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e

# Lists and inspects core dumps collected by systemd
coredumpctl list
coredumpctl gdb <PID>

Takeaway

A missing core file after a crash almost always points to ulimit -c set to 0, the default on most distributions, rather than something unusual about the crash itself. A systemd-managed service ignores /etc/security/limits.conf for this limit exactly like it does for file descriptors, LimitCORE=infinity in the unit file being the only setting that actually matters. Even with the limit correctly configured, core_pattern can silently redirect core dumps to a handler like systemd-coredump, making coredumpctl the entry point worth knowing rather than a core file searched for in the wrong place.