Skip to content

Segfault when requesting /sources during startupΒ #151

@MisterGC

Description

@MisterGC

Problem

The MapViewer crashes with a segmentation fault shortly after startup when a client (e.g. erdblick) requests the /sources endpoint. The crash happens within 1-3 seconds of the HTTP server becoming available.

How to Reproduce

  1. Start MapViewer with any data source config (e.g. a filestore or NDS.Live source)
  2. Open erdblick immediately (or have the browser auto-open on startup)
  3. Erdblick calls /sources to discover available data sources
  4. Container crashes with signal 11

The crash is intermittent β€” it depends on the timing between server startup and the first /sources request. Slower data sources (NDS.Live, large filestores) increase the window.

Observed Behavior

[2026-03-16 18:29:30.451] Config changed. Removing previous datasources.
[2026-03-16 18:29:30.451] Launching NDS.Live datasource for URI filestore:/data/0/map.ndslive
[2026-03-16 18:29:30.468] Webapp: /app/erdblick
[2026-03-16 18:29:30.571] Could not start HttpServer on 0.0.0.0:8089 (timeout)
[2026-03-16 18:29:31.039] ====== Running on port 8089 ======
              NDS MapViewer is ready!
[2026-03-16 18:29:32.946] CRASH DETECTED in mapviewer
[2026-03-16 18:29:32.946] Signal: 11 (segmentation fault)

Stack trace points to Service::info() called from handleSourcesRequest():

#2 mapget::Service::info(...)
#3 mapget::HttpService::Impl::handleSourcesRequest(...)
#4 drogon::internal::HttpBinder<...>::run(...)

Quick investigation results:

The dataSourceInfo_ map in Service::Impl (service.cpp) has no mutex protection:

  • Write β€” addDataSource() (line ~464): dataSourceInfo_[dataSource] = info; β€” no lock held
  • Read β€” getDataSourceInfos() (line ~543): iterates the same map β€” no lock held

The config subscription callback (service.cpp:400-423) calls addDataSource() in a loop, adding sources one by one. Meanwhile, the HTTP server is already accepting requests. A concurrent read+write on std::map is undefined behavior.

Additionally, addDataSource() inserts into the map (line ~464) before workers are fully created (lines ~476-480), so even a single-source config can hit this if the request arrives during worker setup.

/status returns HTTP 200 as soon as the HTTP server binds, before data sources finish loading, which makes it easy for clients to start requesting /sources too early.

A std::shared_mutex around dataSourceInfo_ access (write lock in add/remove, read lock in getDataSourceInfos/getStatistics) would fix the race.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions