1. Apr 30, 2024
  2. Apr 27, 2024
  3. Apr 26, 2024
    • Matthew Fernandez's avatar
      fix: avoid mixing '__sync_*' and '__atomic_*' built-ins on ref-counted pointers · e6e8572c
      Matthew Fernandez authored
      When operating on reference counted pointers that take up a double-word,
      `refcounted_ptr_peek` was using a single-word read as an optimisation because it
      only needs the first word of the data. Meanwhile the other operations on
      reference counted pointers were using double-word compare-and-swap. On x86-64
      with `-mcx16`, this results in near-optimal code: `CMPXCHG16B` for the
      double-word operations and `MOV` for the single-word read.¹ Similar for x86.
      
      Unfortunately on other platforms, this design can result in non-atomic
      operations. To understand why, note that the compiler has a number of options
      for lowering both the `__sync_*` built-ins and the `__atomic_*` built-ins. Two
      of these options are (1) an inline instruction sequence and (2) a call to a
      libatomic function. A constraint is that its choices must interoperate
      correctly. For example, lowering a 16-bit `__atomic_load` to a `MOV` and a
      16-bit `__atomic_store` to a libatomic call (which is typically implemented with
      a per-instance mutex) would be incorrect. The following interleaving could
      occur, assuming X begins with the value 0x0:
      
        1. Thread A calls `__atomic_store` on X
        2. Thread A’s libatomic call takes a lock on X
        3. Thread A writes 0xad into the first byte of X
        4. Thread B loads both bytes of X in a single instruction
        5. Thread A writes 0xde into the second byte of X
        6. Thread A releases the lock on X
      
      It would have been valid for thread B to read either 0x0 (seeing the value
      before A’s store) or 0xdead (seeing the value after A’s store), but it instead
      saw a torn read of 0x00ad. Because the load and store do not agree on the
      protocol for synchronisation, atomicity can be violated.
      
      Crucially the compiler is only required to maintain this compatibility between
      the _same_ built-ins on the _same_ data type. The `__sync_*` built-ins and the
      `__atomic_*` built-ins are not required to use compatible protocols (and indeed
      they do not on x86-64 with `-mcx16`). And operations on a double-word type are
      not required to use a compatible protocol with operations on a single-word type
      (and indeed they do not on x86-64 _without_ `-mcx16`).
      
      The code in `refcounted_ptr_peek` was violating _both_ of these assumptions. On
      x86-64 without `-mcx16` it resulted in racy code, as it also did on ARM64. We
      could try to detect the narrow scenario wherein it is safe to mix built-ins
      because we know exactly which single instructions they will be lowered to (the
      ideal case on x86-64 described in the first paragraph), but this change
      conservatively switches to a double-word read which we know meets the compiler’s
      assumptions.
      
      ¹ `MOV` is atomic on naturally aligned 8-/16-/32-/64-bit data on x86-64.
      e6e8572c
    • Matthew Fernandez's avatar
  4. Apr 25, 2024
    • Matthew Fernandez's avatar
      fix: remove 'sizeof(refcounted_ptr_t) == sizeof(refcounted_ptr)' assumptions · ebbd5fdc
      Matthew Fernandez authored
      As encoded in a static assertion, the verifier assumes
      
        sizeof(refcounted_ptr_t) >= sizeof(struct refcounted_ptr)
      
      However, some locations were implicitly assuming something stronger, that these
      two were equally sized. This stronger property is true on most platforms – the
      double word used for `refcounted_ptr_t` is exactly the same size as the
      reference-counted pointer struct – but on esoteric platforms it may not be. If a
      pointer is e.g. 2 bytes, the struct may end up being 4 bytes while
      `refcounted_ptr_t` is 8 bytes.
      
      To remedy this we need to:
      
        1. Always use `sizeof(struct refcounted_ptr)` in `memcpy` sizes in preference
           to `sizeof(refcounted_ptr_t)` to avoid over-reading/-writing; and
      
        2. Zero-initialise `refcounted_ptr_t` variables into which we are about to
           perform a (possibly short) `memcpy`.
      ebbd5fdc
    • Matthew Fernandez's avatar
      CI: echo machine details as well · 3a37c02d
      Matthew Fernandez authored
      3a37c02d
    • Matthew Fernandez's avatar
      CI: disable Github CodeQL · f6359a0e
      Matthew Fernandez authored
      This has never run in this repository and is currently disabled because there
      was a ≥ 60 day window without commits. It has not been valuable in other C/C++
      projects in which I have used it, so lets just remove it.
      f6359a0e
    • Matthew Fernandez's avatar
      28fb4961
  5. Apr 24, 2024
  6. Apr 23, 2024
  7. Mar 17, 2024
  8. Nov 27, 2023
  9. Nov 15, 2023
  10. Nov 14, 2023
  11. Nov 13, 2023
    • Matthew Fernandez's avatar
      more precise dashes in man pages · 5e799368
      Matthew Fernandez authored
      Groff 1.23 changes the way bare dashes are interpreted:¹
      
        The hyphenation patterns for English have been updated using the
        `hyph-en-us.tex` patterns file from the TeX hyph-utf8 project.  The
        new patterns likely _will_ change the automatic hyphenation break
        points of your English documents.
        …
        The an (man) and doc (mdoc) macro packages no longer remap the -, ',
        and ` input characters to Basic Latin code points on UTF-8 devices,
        but treat them as groff normally does (and AT&T troff before it did)
        for typesetting devices, where they become the hyphen, apostrophe or
        right single quotation mark, and left single quotation mark,
        respectively.  This change is expected to expose glyph usage errors in
        man pages.  See the "PROBLEMS" file for a recipe that will conceal
        these errors.  A better long-term approach is for man pages to adopt
        correct input practices; the man pages groff_man_style(7),
        groff_char(7), and man-pages(7) (subsection "Generating optimal
        glyphs"; from the Linux man-pages project) contain such instructions.
        Doing so also improves man page typography when formatting for PDF.
      
      This is already causing controversy and Debian has patched it back to the old
      behavior.² LWN has a good summary of why such a seemingly minor display change
      has acute negative consequences.³
      
      ¹ https://lists.gnu.org/archive/html/info-gnu/2023-07/msg00001.html
      ² https://lwn.net/ml/debian-devel/ZS0aV4XyJH+O1o%2Fc@riva.ucam.org/
      ³ https://lwn.net/Articles/947941/
      5e799368
    • Matthew Fernandez's avatar
      58899d78
  12. Sep 24, 2023
  13. May 22, 2023
  14. May 09, 2023