Commits on Source 15

  • cznic's avatar
    nuc64: auto deps · ccaf682c
    cznic authored
    ccaf682c
  • cznic's avatar
    modernc.org/libc: nuc64 auto generate · 1aded7cd
    cznic authored
    1aded7cd
  • cznic's avatar
    modernc.org/libc: pi32 auto generate · 61e8485a
    cznic authored
    61e8485a
  • cznic's avatar
    modernc.org/libc: pi64 auto generate · f6b2610a
    cznic authored
    f6b2610a
  • cznic's avatar
    modernc.org/libc: ppc64le auto generate · 234b2163
    cznic authored
    234b2163
  • cznic's avatar
    modernc.org/libc: linux_loong64b auto generate · 05e89648
    cznic authored
    05e89648
  • cznic's avatar
    modernc.org/libc: riscv64 auto generate · 7cdf9f2b
    cznic authored
    7cdf9f2b
  • cznic's avatar
    libc_musl: fix lost-wakeup deadlock in ___lock/___unlock · 852ba3a8
    cznic authored
    ___lock/___unlock emulated a C mutex using an atomic lock-word fast path
    plus a throwaway hand-off object stored in a map. When an unlocker took
    locksMu before a contending locker had registered its hand-off, ___unlock
    synthesized one and immediately discarded it; the waiter then blocked on a
    fresh, never-unlocked mutex forever, and the lock word was left non-zero, so
    every subsequent ___lock on that address also blocked. The process wedged
    permanently at zero CPU.
    
    The window is reachable through the exported API alone: localtime, localtime_r
    and mktime all take the single process-global timezone lock (_lock4) via
    __secs_to_zone on every call, so goroutines calling them concurrently can hit
    it. Reported against modernc.org/quickjs evaluating JS Date local-time getters.
    
    Replace the scheme with a per-address sync.Mutex, created lazily and
    reference-counted for cleanup. The opaque C lock word is no longer touched
    (nothing reads it outside these two functions); routing all mutual exclusion
    through the per-address mutex makes the hand-off race-free, so a release
    delivered before the waiter blocks is no longer lost.
    
    Add TestIssue51: a mutual-exclusion stress on ___lock/___unlock plus a
    concurrent localtime_r stress; both clean under -race.
    
    Fixes: #51
    
    Co-Authored-By: default avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
    852ba3a8
  • cznic's avatar
    builder.json: s/arm$/arm\$/ · 62087adb
    cznic authored
    62087adb
  • cznic's avatar
    modernc.org/libc: e5-1650 auto generate · c62e387f
    cznic authored
    c62e387f
  • cznic's avatar
    modernc.org/libc: fix __atomic_compare_exchange* reporting a bogus old value on failure · e20e49ab
    cznic authored
    The failure path re-read *ptr in a separate step instead of reporting the
    value observed during the failed comparison. C11 7.17.7.4 puts that update
    inside the atomic read-modify-write ("Atomically, compares ... and if false,
    updates the value in expected with the value pointed to by object"), and the
    hardware does exactly that: cmpxchg loads the actual value in the same
    instruction.
    
    If *ptr transiently reverted to the expected value inside the window between
    the failed CAS and the separate reload, the helper returned failure while
    writing the expected value back into *expected. Callers spinning on
    
    	while (atomic_compare_exchange_strong(&lock, &zero, 1) != 0) ;
    
    then left the loop without having acquired anything, because that idiom exits
    precisely when the reported old value equals the expected one.
    
    Restore the invariant that a failure reports a witness != old by retrying
    while the observed value is still old. A strong CAS that failed against old
    means *p != old at that instant, so a witness equal to old is never a valid
    failure report; and if the value did revert, a cmpxchg issued at that moment
    would have succeeded, making the retry more faithful than the bogus report.
    
    Affects the lock-free Int32/Uint32/Int64/Uint64 helpers. The Int8/Int16 and
    __c11_atomic_compare_exchange_strong* variants read the witness under the same
    mutex that guards the compare and were already correct.
    
    Found via modernc.org/libquickjs CI builders wedging at 100% CPU for 19+ hours
    in test262's Atomics agent tests, which use exactly that spin idiom. Hang rates
    on a 2-CPU linux/386 box, 200 runs of a single test: 20/200 (BigInt64Array) and
    16/200 (Int32Array) before, 0/200 after.
    
    TestIssue52/failure_witness fails on the old code (order 10^3 violations per
    2000000 attempts on amd64, 19028/2000000 on 386) and passes on the new. Only
    the contended case can observe this: TestIssue52/uncontended_semantics passes
    even on the broken code, which is why it went unnoticed.
    
    Closes #52
    
    Co-Authored-By: default avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
    e20e49ab
  • cznic's avatar
    modernc.org/libc: s390x auto generate · e1e8eb7d
    cznic authored
    e1e8eb7d
  • cznic's avatar
    modernc.org/libc: fix readdir returning deleted entries on openbsd · 342f5ac3
    cznic authored
    getdirentries(2) reports records of deleted files with d_fileno set to zero
    and readdir(3) must not return them. On FFS such a record survives an unlink
    whenever it is the first one in a directory block, so any directory larger
    than a single 512-byte block reported ghost entries for files that were
    already gone.
    
    That made Tcl's glob (via libtcl8.6) see deleted files, causing the
    modernc.org/libsqlite3 openbsd/amd64 test failures delete_db-1.3.1,
    delete_db-1.4.1, multiplex-2.4.5, multiplex-5.3.prep and quota-5.3.prep.
    The failures only showed up in full-suite runs, once the shared working
    directory had grown past one block.
    
    Also stop iterating on a malformed d_reclen rather than spinning on it,
    matching the checks in OpenBSD's _readdir_unlocked().
    
    Co-Authored-By: default avatarClaude Opus 4.8 (1M context) <noreply@anthropic.com>
    342f5ac3
  • cznic's avatar
    modernc.org/libc: reject a Go string in VaList instead of copying its header · 6596c7da
    cznic authored
    VaList takes anything outside int/uint/int32/.../float64/uintptr through a
    default case that memcpy's reflect.TypeOf(v).Size() bytes of the value. For a
    Go string that copies the 16 byte {ptr, len} header into the va_list. C reads
    the first word as a char* and, Go strings not being NUL terminated, vsnprintf
    runs past the end of the string, appending whatever sits next to it on the Go
    heap. The header is also wider than the 8 bytes a caller sizes a va_list slot
    at, so the write itself overruns the allocation.
    
    That is how modernc.org/quickjs leaked Go runtime internals into a
    script-visible Error.message, see quickjs#14.
    C has no string type, so ccgo never emits one here; every occurrence is hand
    written and always a bug. Panic instead of corrupting silently, in both the
    ccgo/v3 (etc.go) and ccgo/v4 (rtl.go) copies. The default case stays as it is,
    that is what carries a C struct or array passed by value.
    
    Callers must pass CString(s). Note that a modernc.org/quickjs older than
    v0.22.0 trips this panic on any host function error.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    6596c7da
  • cznic's avatar
    libc_musl: keep ___lock state in the C lock word so it cannot outlive it · 04bd0c66
    cznic authored
    852ba3a8 moved musl lock state out of the C lock word *p and into a
    process-global map keyed on the word's address. musl's freeaddrinfo
    deliberately frees the buffer holding its lock word while still holding
    that lock and never unlocks:
    
    	LOCK(b->lock);
    	if (!(b->ref -= cnt)) free(b);
    	else UNLOCK(b->lock);
    
    That is correct in C, because the word is inside the block and dies with
    it. With the state in a global map the entry outlived the free, still
    locked, so when the allocator handed the same address to a later
    getaddrinfo the next freeaddrinfo blocked forever in ___lock at zero CPU,
    with no error. Deterministic on linux/386 and linux/arm, where the
    allocator recycles the address; latent on linux/amd64, which escapes on
    allocator behaviour rather than by design. Reported as libtcl9.0's 386 and
    arm builders no longer completing test runs.
    
    Put all lock state back in *p, as musl does: 0 free, 1 held, 2 held with a
    waiter possibly parked, driven by a_cas/swap. Freeing the memory then
    discards the state exactly as C expects, and a recycled calloc'd block
    starts out unlocked. Blocking uses a parking lot keyed by address in place
    of musl's futex: lockWait re-checks *p under lockParkMu and ___unlock
    stores to *p before lockWake takes that mutex, so a release landing before
    the waiter parks is seen as a value change rather than lost, which is what
    made #51 reachable. Parking lot entries exist only while a goroutine is
    really parked, so an abandoned lock leaves nothing behind and the hazard is
    gone generically, not just for freeaddrinfo. The global mutex is off the
    fast path, and an unbalanced ___unlock is now inert instead of a nil
    dereference.
    
    Add TestMuslLockLifetime: a recycled lock word, parking lot reclamation
    over the uncontended, contended and abandoned paths, an unbalanced unlock,
    and a bounded getaddrinfo/freeaddrinfo loop. TestIssue51 keeps its lock
    word in a package-level Go var; the race detector ignores atomics outside
    the Go arena and data segments, so a word in libc-allocated memory would
    carry no happens-before edge to the Go state a critical section guards.
    The real static musl lock words are package-level [1]int32, so this also
    matches them.
    
    Verified on linux/386 and linux/arm, where the reproducer completes and the
    unfixed ___lock hangs on the second iteration: go test -race, TestLibc
    (473 files, 0 build and 0 exec failures), build_all_targets across all
    targets and tags, and modernc.org/libtcl9.0 both for httpProxy.test and for
    its full suite (170 test files, 68391 assertions, 0 failed on each).
    
    Retract v1.74.2 and v1.74.3, which carry the defect.
    
    Co-Authored-By: default avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
    04bd0c66
Loading
Loading