{"id":18627499,"url":"https://github.com/yugr/sortcheck","last_synced_at":"2025-10-03T20:12:55.247Z","repository":{"id":41437271,"uuid":"47511370","full_name":"yugr/sortcheck","owner":"yugr","description":"Tool for detecting violations of ordering axioms in qsort/bsearch callbacks.","archived":false,"fork":false,"pushed_at":"2025-01-25T03:00:53.000Z","size":258,"stargazers_count":52,"open_issues_count":0,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-25T13:07:19.123Z","etag":null,"topics":["dynamic-analysis","program-analysis","qsort","runtime-verification"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yugr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2015-12-06T19:55:39.000Z","updated_at":"2025-04-04T18:57:37.000Z","dependencies_parsed_at":"2024-12-28T19:25:24.341Z","dependency_job_id":"ca601332-dfd6-46c7-8234-e86ad29ae804","html_url":"https://github.com/yugr/sortcheck","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yugr/sortcheck","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yugr%2Fsortcheck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yugr%2Fsortcheck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yugr%2Fsortcheck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yugr%2Fsortcheck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yugr","download_url":"https://codeload.github.com/yugr/sortcheck/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yugr%2Fsortcheck/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278219802,"owners_count":25950355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-03T02:00:06.070Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dynamic-analysis","program-analysis","qsort","runtime-verification"],"created_at":"2024-11-07T04:42:36.440Z","updated_at":"2025-10-03T20:12:55.217Z","avatar_url":"https://github.com/yugr.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![License](http://img.shields.io/:license-MIT-blue.svg)](https://github.com/yugr/sortcheck/blob/master/LICENSE.txt)\n[![Build Status](https://github.com/yugr/sortcheck/actions/workflows/ci.yml/badge.svg)](https://github.com/yugr/sortcheck/actions)\n[![Codecov coverage](https://img.shields.io/codecov/c/github/yugr/sortcheck.svg)](https://codecov.io/gh/yugr/sortcheck)\n[![Total alerts](https://img.shields.io/lgtm/alerts/g/yugr/sortcheck.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/yugr/sortcheck/alerts/)\n[![Coverity Scan](https://scan.coverity.com/projects/19944/badge.svg)](https://scan.coverity.com/projects/yugr-sortcheck)\n\n# What is this?\n\nSortChecker is a tool for detecting violations\nof [ordering axioms](http://pubs.opengroup.org/onlinepubs/009695399/functions/qsort.html)\nin comparison functions passed to `qsort`\n(also `bsearch`, `lfind`, etc.). For complex data structures it's very\neasy to violate one of the requirements. Such violations cause\nundefined behavior and may lead to all sorts of runtime\nerrors (including [unexpected results](https://groups.google.com/d/topic/golang-checkins/w4YWUgBhjJ0),\n[inconsistent results across different platforms](https://gcc.gnu.org/ml/gcc/2017-07/msg00078.html)\nor even [aborts](https://bugzilla.samba.org/show_bug.cgi?id=3959))\n(also [here](https://stackoverflow.com/questions/2441045/bewildering-segfault-involving-stl-sort-algorithm),\nsee [this answer](https://stackoverflow.com/a/24048654/2170527),\n[Qualys analysis](https://www.openwall.com/lists/oss-security/2024/01/30/7) and\n[my slides](https://github.com/yugr/CppRussia/blob/master/2023/EN.pdf) for explanations).\n\nThe tool works by intercepting `qsort` and friends through `LD_PRELOAD`\nand performing various checks prior to passing control to libc.\nIt could be applied to both C and C++ programs although for the\nlatter `std::sort` and `std::binary_search` are more typical\n(use my [SortChecker++](https://github.com/yugr/sortcheckxx) tool\nto diagnose errors in them).\n\nThe tool is quite robust - I've successfully\nbooted stock Ubuntu 14, Fedora 22 and Debian chroot and bootstrapped\nGCC 4.9.\n\nThe project is MIT-licensed. It has no fancy dependencies,\njust Glibc and Bash.\n\n# What are current results?\n\nI've done some basic testing of Ubuntu 14.04 and Fedora 22 distro\nunder SortChecker (open file/web browsers, navigate system menus,\ninstall various apps, etc.).\n\nThe tool has found errors in many programs.  Here are some trophies:\n* [Libxt6: Invalid comparison function](https://bugs.freedesktop.org/show_bug.cgi?id=93273)\n* [Libharfbuzz: Invalid comparison function](https://bugs.freedesktop.org/show_bug.cgi?id=93274) (fixed)\n* [Libharfbuzz: Unsorted array used in bsearch](https://bugs.freedesktop.org/show_bug.cgi?id=93275) (fixed)\n* [Cpio: HOL\\_ENTRY\\_PTRCMP triggers undefined behavior](http://savannah.gnu.org/bugs/index.php?46638)\n* [GCC: reload\\_pseudo\\_compare\\_func violates qsort requirements](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68988) (fixed)\n* [GCC: libbacktrace: bsearch over unsorted array in unit\\_addrs\\_search](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69050) (intentional)\n* [GCC: Fix intransitive comparison in dr\\_group\\_sort\\_cmp](https://gcc.gnu.org/ml/gcc-patches/2015-12/msg02141.html) ([was already fixed on trunk](https://gcc.gnu.org/ml/gcc-patches/2015-11/msg02444.html))\n* [GCC: Fix qsort ordering violation in tree-vrp.c](https://gcc.gnu.org/ml/gcc-patches/2017-07/msg00882.html) ([confirmed](https://gcc.gnu.org/ml/gcc-patches/2017-07/msg00897.html))\n* [dpkg: pkg\\_sorter\\_by\\_listfile\\_phys\\_offs violates qsort requirements](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=808912) (fixed)\n* [Fontforge: line\\_pt\\_cmp violates qsort ordering axioms](https://github.com/fontforge/fontforge/issues/2602)\n* [Flexible I/O Tester: Invalid comparison function](https://github.com/axboe/fio/issues/140) (fixed)\n* [Infernal: Inconsistent results from qsort callback](https://github.com/EddyRivasLab/infernal/issues/11) (fixed)\n* [Graphicsmagick: Inconsistent results from qsort callback](https://sourceforge.net/p/graphicsmagick/bugs/562/) (fixed)\n* [PostGIS: Inconsistent results from qsort callback](https://trac.osgeo.org/postgis/ticket/4093) (fixed)\n* [Grass: Inconsistent results from qsort callback in g.mkfontcap](https://trac.osgeo.org/grass/ticket/3564) (fixed)\n\nI haven't seen a noticeable slowdown when working in a fully checked\ndistro or building C++ projects with a checked compiler.\n\n# Usage\n\nYou do not need to rebuild your app to test it under SortChecker.\nJust run with preloaded `libsortcheck.so`:\n\n```\n$ LD_PRELOAD=libsortcheck.so myapp ...\n```\n\n(you'll probably want to combine this with some kind of regression\nor random/fuzz testing to achieve good coverage,\nalso see the `shuffle` and `start` options below).\n\nYou could also use a helper script `sortcheck` to do this for you:\n\n```\n$ sortcheck myapp ...\n```\n\nTo debug the issue, you can run with\n\n```\n$ SORTCHECK_OPTIONS=raise=1 sortcheck myapp ...\n```\n\nand then examine generated coredump in `gdb`.\n\nBy default SortChecker enables a set of common checks which should\nbe enough for most users. You can also customize it's behavior\nthrough `SORTCHECK_OPTIONS` environment variable which is\na colon-separated list of option assignments e.g.\n\n```\n$ export SORTCHECK_OPTIONS=debug=1:max_errors=10\n```\n\nYou can also put option string to `/SORTCHECK_OPTIONS` file\n(this is particularly useful for testing of daemon processes).\n\nSupported options are\n* `max_errors` - maximum number of errors to report (default 10)\n* `debug` - print debug info (default false)\n* `print_to_file` - print warnings to specified file (rather\nthan default stderr)\n* `print_to_syslog` - print warnings to syslog instead of stderr\n(default false)\n* `do_report_error` - print reports (only used for benchmarking,\ndefault true)\n* `raise` - raise signal on detecting violation (useful for\ninspecting issues in debugger)\n* `sleep` - sleep for N seconds before printing error and continuing\n(may be useful for attaching with gdb and examining the situation)\n* `check` - comma-separated list of checks to perform;\navailable options are\n  * `default` - default set of checks (see below)\n  * `basic` - check that comparison functions return stable results\n  and does not modify inputs (enabled by default)\n  * `sorted` - check that arrays passed to bsearch are sorted (enabled\n  by default)\n  * `symmetry` - check that cmp(x,y) == -cmp(y,x) (enabled by default)\n  * `transitivity` - check that if x \u003c y \u0026\u0026 y \u003c z, then x \u003c z\n  (enabled by default)\n  * `reflexivity` - check that cmp(x,x) == 0 (disabled by default,\n  on the other hand may trigger on otherwise undetected asymmetry bugs)\n  * `unique` - check that cmp does not compare different objects\n  as equal (to avoid [random orderings on different platforms](https://gcc.gnu.org/ml/gcc/2017-07/msg00078.html))\n  * `good_bsearch` - bsearch uses a restricted (non-symmetric) form\n  of comparison function so some checks are not generally applicable;\n  this option tells SortChecker that it should test bsearch more\n  aggressively (unsafe so disabled by default). Note that this\n  option may cause runtime errors or crashes if applied\n  inappropriately.\n  * for each option `XYZ` there's a dual `no_XYZ` (which disables\n  corresponding check)\n* `shuffle` - reshuffle array before checking with given seed;\n  a value of `rand` will use random seed\n  (helps find bugs which are not located at start of array)\n* `start` - check the `start`-th group of 32 leading elements (default 0);\n  a value of `rand` will select random group\n\nNote that on Darwin you need to use `DYLD_INSERT_LIBRARIES` and `DYLD_FORCE_FLAT_NAMESPACE`\nand may also need to disable System Integrity Protection.\nTo verify that Sortcheck works on Darwin, run with `SORTCHECK_OPTIONS=debug=1`.\n\n# Applying to full distribution\n\nYou can run full Linux distro under SortChecker:\n* add full path to `libsortcheck.so` to `/etc/ld.so.preload`\n* create a global config:\n\n  ```\n  $ echo print_to_syslog=1:check=default:shuffle=rand | sudo tee /SORTCHECK_OPTIONS \n  $ sudo chmod a+r /SORTCHECK_OPTIONS\n  ```\n\n* reboot\n\nDue to randomized order of checks it makes sense to check for errors and\nreboot several times to detect more errors.\n\nDisclaimer: in this mode libsortcheck.so will be preloaded to\nall your processes so any malfunction may permanently break your\nsystem. It's highly recommended to backup the disk or make\nVM snapshot.\n\n# Build\n\nTo build the tool, simply run make from project top directory.\nMakefile supports various candies (e.g. AddressSanitizer,\ndebug build, etc.) - run `make help` for mode details.\n\nIf you enable AddressSanitizer you'll need to add libasan.so\nto `LD_PRELOAD` (before `libsortcheck.so`).\n\nTo test the tool, run `make check`. Note that I've myself only\ntested SortChecker on Ubuntu and Fedora.\n\n# Known issues\n\n* SortChecker is not fully thread-safe yet (should be easy to fix though)\n* SortChecker supports Linux, BSD and Darwin (relies on `LD_PRELOAD`)\n\n# Future plans\n\nThe tool only supports C now which rules out most of C++ code\nbecause it uses (inline) `std::sort` and `std::binary_search`\n(and other similar APIs). For those see another tool\n[SortChecker++](https://github.com/yugr/sortcheckxx)\nwhich does a simple compile-time instrumentation via Clang.\n\nIt would be great to make SortChecker a part of standard debuggin tool\nlike UBsan. Here's a [discussion](http://lists.llvm.org/pipermail/llvm-dev/2016-January/093835.html)\nin LLVM mailing list which unfortunately didn't go too far.\n\nIt may also make sense to check other popular sorting APIs:\n* `qsort_s`, `bsearch_s` (are they availabile/used?)\n* `fts_open`, `scandir`\n* Berkeley DB's `set_bt_compare`, `set_dup_compare`, etc.\n* Glib2's `g_qsort_with_data` and other users of GCompareFunc/GCompareDataFunc\n* Gnulib's `gl_listelement_compar_fn` and friends\n* Libiberty's `splay_tree` API\n* OpenSSL's `objects.h` API\n* etc.\n\nHere's less high-level stuff (sorted by priority):\n* ensure that code is thread-safe (may need lots of platform-dependent code for atomics...)\n* print complete backtrace rather than just address of caller (libunwind?)\n* other minor TODO/FIXME are scattered all over the codebase\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyugr%2Fsortcheck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyugr%2Fsortcheck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyugr%2Fsortcheck/lists"}