openssl for i586 #31793
Replies: 15 comments 8 replies
-
|
What do you get from |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Are you able to build a debug version of OpenSSL with a custom config option? If so can you rebuild OpenSSL with the "enable-trace" option switched on? Once built rerun the same command you tried above just to confirm that it is still failing in the same way. Then try: Please post the output you get here. |
Beta Was this translation helpful? Give feedback.
-
|
I applied the patch and re-ran the command. |
Beta Was this translation helpful? Give feedback.
-
|
um: I think that uri is incorrect. uri_file_stat() expects that the uri either be a direct file name (i.e. /tmp/asdf), or a fully qualified file uri (i.e. file:///tmp/asdf) |
Beta Was this translation helpful? Give feedback.
-
That's not the issue here. (I mean it is an issue, but it is not the issue). We should not be seeing the No store loader found error. We seem to have the case where |
Beta Was this translation helpful? Give feedback.
-
|
@uglyoldbob thanks for applying the patch and running it. It gives more details about where the failure occurs, but we need to narrow in a bit further. Can you apply the following (on top of the previous patch) and repeat? From ae266951e82b9d5056b7af474a93e380a882953b Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.foundation>
Date: Fri, 3 Jul 2026 16:16:20 +0100
Subject: [PATCH] Add deeper namemap/hashtable diagnostics for i586 file-store
bug
Trace the namemap insert/lookup for the 'file' scheme: struct sizes,
key buffer, computed hash, and an immediate reverify after insert.
Gated on 'file' to keep the output small.
Assisted-by: Claude Code:claude-opus-4-8
---
crypto/core_namemap.c | 35 +++++++++++++++++++++++++++++++++++
crypto/property/property.c | 3 ---
crypto/store/store_meth.c | 10 +++++++++-
3 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/crypto/core_namemap.c b/crypto/core_namemap.c
index 8e646c3bcc..f6677c97b9 100644
--- a/crypto/core_namemap.c
+++ b/crypto/core_namemap.c
@@ -7,9 +7,11 @@
* https://www.openssl.org/source/license.html
*/
+#include <stdio.h>
#include "internal/namemap.h"
#include "internal/tsan_assist.h"
#include "internal/hashtable.h"
+#include "internal/hashfunc.h"
#include "internal/sizes.h"
#include "crypto/context.h"
@@ -272,8 +274,25 @@ static int namemap_add_name(OSSL_NAMEMAP *namemap, int number,
HT_INIT_KEY(&key);
HT_SET_KEY_STRING_CASE(&key, name, name);
+
+ /* Only trace the scheme we're chasing, to keep the output manageable */
+ if (strcmp(name, "file") == 0)
+ fprintf(stderr, "DEBUG namemap_add_name: namemap=%p ht=%p inserting '%s' "
+ "sizeof(HT_KEY)=%zu sizeof(NAMENUM_KEY)=%zu "
+ "keysize=%zu keybuf=%p hash=%llu\n",
+ (void *)namemap, (void *)namemap->namenum_ht, name,
+ sizeof(HT_KEY), sizeof(NAMENUM_KEY),
+ (size_t)key.key_header.keysize,
+ (void *)key.key_header.keybuf,
+ (unsigned long long)ossl_fnv1a_hash(key.key_header.keybuf,
+ key.key_header.keysize));
+
val.value = (void *)(intptr_t)number;
ret = ossl_ht_insert(namemap->namenum_ht, TO_HT_KEY(&key), &val, NULL);
+
+ if (strcmp(name, "file") == 0)
+ fprintf(stderr, "DEBUG namemap_add_name: insert rc=%d\n", ret);
+
if (!ossl_assert(ret != 0)) /* cannot happen as we are under write lock */
return 0;
if (ret < 1) {
@@ -281,6 +300,22 @@ static int namemap_add_name(OSSL_NAMEMAP *namemap, int number,
ERR_raise(ERR_LIB_CRYPTO, CRYPTO_R_TOO_MANY_NAMES);
return 0;
}
+
+ /* Immediately verify the lookup works */
+ if (strcmp(name, "file") == 0) {
+ NAMENUM_KEY lkey;
+ int verify;
+
+ HT_INIT_KEY(&lkey);
+ HT_SET_KEY_STRING_CASE(&lkey, name, name);
+ fprintf(stderr, "DEBUG namemap_add_name: lookup key keysize=%zu keybuf=%p hash=%llu\n",
+ (size_t)lkey.key_header.keysize, (void *)lkey.key_header.keybuf,
+ (unsigned long long)ossl_fnv1a_hash(lkey.key_header.keybuf,
+ lkey.key_header.keysize));
+ verify = ossl_namemap_name2num(namemap, name);
+ fprintf(stderr, "DEBUG namemap_add_name: immediate reverify '%s' -> id=%d\n",
+ name, verify);
+ }
return number;
}
diff --git a/crypto/property/property.c b/crypto/property/property.c
index 7a3e4ca54f..37a0240a79 100644
--- a/crypto/property/property.c
+++ b/crypto/property/property.c
@@ -324,9 +324,6 @@ int ossl_method_store_add(OSSL_METHOD_STORE *store, const OSSL_PROVIDER *prov,
int ret = 0;
int i;
- fprintf(stderr, "DEBUG ossl_method_store_add: nid=%d properties=%s store=%p method=%p\n",
- nid, properties ? properties : "(null)", (void *)store, method);
-
if (nid <= 0) {
fprintf(stderr, "DEBUG ossl_method_store_add: nid <= 0, returning 0\n");
return 0;
diff --git a/crypto/store/store_meth.c b/crypto/store/store_meth.c
index d4c93b0ce5..74bde3799c 100644
--- a/crypto/store/store_meth.c
+++ b/crypto/store/store_meth.c
@@ -170,6 +170,8 @@ static int put_loader_in_store(void *store, void *method,
fprintf(stderr, "DEBUG put_loader_in_store: namemap is NULL\n");
return 0;
}
+ fprintf(stderr, "DEBUG put_loader_in_store: scheme='%s' namemap=%p\n",
+ scheme, (void *)namemap);
if ((id = ossl_namemap_name2num(namemap, scheme)) == 0) {
fprintf(stderr, "DEBUG put_loader_in_store: namemap lookup for '%s' returned 0\n",
scheme);
@@ -275,9 +277,15 @@ static void *construct_loader(const OSSL_ALGORITHM *algodef,
OSSL_LIB_CTX *libctx = ossl_provider_libctx(prov);
OSSL_NAMEMAP *namemap = ossl_namemap_stored(libctx);
const char *scheme = algodef->algorithm_names;
- int id = ossl_namemap_add_name(namemap, 0, scheme);
+ int id;
void *method = NULL;
+ fprintf(stderr, "DEBUG construct_loader: scheme='%s' namemap=%p libctx=%p\n",
+ scheme, (void *)namemap, (void *)libctx);
+ id = ossl_namemap_add_name(namemap, 0, scheme);
+ fprintf(stderr, "DEBUG construct_loader: ossl_namemap_add_name('%s') -> id=%d\n",
+ scheme, id);
+
if (id != 0)
method = loader_from_algorithm(id, algodef, prov);
--
2.43.0 |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
|
Just to confirm @uglyoldbob your tests above, are you testing on 3.5.5 or 3.5.6? I ask because we fixed an alignment issue in the hashtable code (which impacted the namemap) in commit 75a3b8f, which impacted 32 bit systems. I know you said this was happening on both 3.5.5 and 3.5.6, but its probably worth restricting your testing to 3.5.6 specifically, just to ensure thats not causing a problem. Additionally, the hashtable is optimized by ensuring that all the hopscotch tables are sized and aligned to match the cache line size of the cpu its executing on, which is, in almost all modern cpus, 64 bytes. But IIRC i586 has a 32 byte cache line. It might be worth applying this patch: Thats not a real fix of course, we'll have to make that conditional on the arch being built for, but it would be a good data point to have, in the event that a neighborhood in the hashtable is spanning a cacheline, and thats somehow impacting the atomic operations that the hashtable uses. |
Beta Was this translation helpful? Give feedback.
-
|
Thanks @uglyoldbob. This seems to point to some weirdness in the hashtable implementation. @nhorman is far more qualified to comment on that area of code than I am. However here is what I am seeing:
The file scheme reaches construct_loader with a valid namemap (0x887950) and libctx. So the default provider is active and offering the file store loader
The insert into namemap 0x887950 / hashtable 0x8879a0 succeeds (rc=1). Struct sizes are the expected 32‑bit values (HT_KEY=8 vs 16 on x86‑64), keysize=64, and the hash is computed.
Immediately after the successful insert, in the same namemap, under the same write lock, the lookup returns 0 - not found, i.e. The value goes into the hashtable and cannot be read back out. @nhorman says:
My working assumption has been 3.5.6 because the error output is showing a 3.5.6 path:
It would be good to get this definitively confirmed. I think it would be helpful to do another round of debug logging this time in the hashtable implementation. @uglyoldbob - please can you apply the following and try again: From b4aef073fa4ff2de57f5adab6ba373c52be48052 Mon Sep 17 00:00:00 2001
From: Matt Caswell <matt@openssl.foundation>
Date: Mon, 6 Jul 2026 08:45:57 +0100
Subject: [PATCH] Instrument ossl_ht_insert/ossl_ht_get for the i586 namemap
bug
Trace the store and lookup of the 'file' entry: neigh/slot, hash and
value round-trip on insert, and compare_hash/match_key on get. Gated
on the file hash.
Assisted-by: Claude Code:claude-opus-4-8
---
crypto/hashtable/hashtable.c | 41 ++++++++++++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/crypto/hashtable/hashtable.c b/crypto/hashtable/hashtable.c
index 8b9f9cc0d9..b8d26be702 100644
--- a/crypto/hashtable/hashtable.c
+++ b/crypto/hashtable/hashtable.c
@@ -50,12 +50,16 @@
* searched for a match until an empty entry is found.
*/
+#include <stdio.h>
#include <string.h>
#include <internal/rcu.h>
#include <internal/hashtable.h>
#include <internal/hashfunc.h>
#include <openssl/rand.h>
+/* Hash of the "file" store scheme; used only to gate debug output */
+#define DBG_FILE_HASH 12890292847699326835ULL
+
/*
* gcc defines __SANITIZE_THREAD__
* but clang uses the feature attributes api
@@ -588,6 +592,21 @@ not_found:
h->wpd.value_count++;
ossl_rcu_assign_ptr(&md->neighborhoods[neigh_idx].entries[empty_idx].value,
&newval);
+
+ if (hash == DBG_FILE_HASH) {
+ uint64_t rbhash = 0;
+ struct ht_internal_value_st *rbval;
+
+ (void)CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[empty_idx].hash,
+ &rbhash, h->atomic_lock);
+ rbval = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[empty_idx].value);
+ fprintf(stderr, "DEBUG ossl_ht_insert[file]: stored at neigh=%llu slot=%zu; "
+ "readback hash=%llu (match=%d) value=%p (match=%d) value_count=%zu\n",
+ (unsigned long long)neigh_idx, empty_idx,
+ (unsigned long long)rbhash, rbhash == hash,
+ (void *)rbval, rbval == newval, h->wpd.value_count);
+ }
+
return 1;
}
@@ -675,11 +694,25 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key)
md = ossl_rcu_deref(&h->md);
neigh_idx = neigh_idx_start = hash & md->neighborhood_mask;
+
+ if (hash == DBG_FILE_HASH)
+ fprintf(stderr, "DEBUG ossl_ht_get[file]: hash=%llu neigh_idx=%llu "
+ "mask=%llu NEIGHBORHOOD_LEN=%zu lockfree8=%d atomic_lock=%p\n",
+ (unsigned long long)hash, (unsigned long long)neigh_idx,
+ (unsigned long long)md->neighborhood_mask, (size_t)NEIGHBORHOOD_LEN,
+ (int)__atomic_is_lock_free(8, &md->neighborhoods[neigh_idx].entries[0].hash),
+ (void *)h->atomic_lock);
+
do {
PREFETCH_NEIGHBORHOOD(md->neighborhoods[neigh_idx]);
for (j = 0; j < NEIGHBORHOOD_LEN; j++) {
ival = ossl_rcu_deref(&md->neighborhoods[neigh_idx].entries[j].value);
if (ival == NULL) {
+ if (hash == DBG_FILE_HASH)
+ fprintf(stderr, "DEBUG ossl_ht_get[file]: neigh=%llu j=%zu EMPTY "
+ "(lockless_reads=%d -> %s)\n",
+ (unsigned long long)neigh_idx, j, lockless_reads,
+ lockless_reads ? "return NULL" : "continue");
if (lockless_reads)
/* lockless_reads implies no deletion, we can break out */
return NULL;
@@ -688,6 +721,11 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key)
if (!CRYPTO_atomic_load(&md->neighborhoods[neigh_idx].entries[j].hash,
&ehash, h->atomic_lock))
return NULL;
+ if (hash == DBG_FILE_HASH)
+ fprintf(stderr, "DEBUG ossl_ht_get[file]: neigh=%llu j=%zu ehash=%llu "
+ "compare_hash=%d match_key=%d\n",
+ (unsigned long long)neigh_idx, j, (unsigned long long)ehash,
+ compare_hash(hash, ehash), match_key(&ival->value.key, key));
if (compare_hash(hash, ehash) && match_key(&ival->value.key, key))
return (HT_VALUE *)ival;
}
@@ -697,6 +735,9 @@ HT_VALUE *ossl_ht_get(HT *h, HT_KEY *key)
neigh_idx = (neigh_idx + 1) & md->neighborhood_mask;
} while (neigh_idx != neigh_idx_start);
+ if (hash == DBG_FILE_HASH)
+ fprintf(stderr, "DEBUG ossl_ht_get[file]: exhausted search, returning NULL\n");
+
return NULL;
}
--
2.43.0 |
Beta Was this translation helpful? Give feedback.
-
|
I am using openssl 3.5.6. I applied the change for CACHE_LINE_BYTES, but did not see any change in behavior, so I reverted that change. |
Beta Was this translation helpful? Give feedback.
-
|
I compiled and ran the atomic test program. Here is the disassembly of it (with the same gcc compiler used to build openssl 3.5.6) Here is what happens when I run it. And here is some disassembly from build/crypto/libcrypto-lib-threads_pthread.o |
Beta Was this translation helpful? Give feedback.
-
|
I tried compiling with clang, that didn't help so I reverted back to using gcc. |
Beta Was this translation helpful? Give feedback.
-
|
Thats just wild: gcc is using floating point instructions to atomic 64 bit loads/stores. From what I read, its done to avoid having to use the LOCK prefix on instructions, which is much slower. Using -DBROKEN_CLANG_ATOMICS: It makes sense that would work as it backs off everything in the CRYPTO_atomic api to use locks rather than atomic operations. I'm not sure whats going on here exactly, but it definitely seems like something about those instructions use is transiently causing some corruption (maybe a misaligned pointer address? i don't know). But I wonder if the better part of sanity here is to mark i586 in a way that it uses locking rather than atomics entirely. @mattcaswell ? |
Beta Was this translation helpful? Give feedback.
-
|
So, this is definitive. This isn't an OpenSSL bug:
This is entirely unexpected and clearly shows that the "store" operation has failed to store correctly!! It's surprising that gcc uses the FPU (fildll/fistpll) to do a 64-bit atomic at all. But, IIUC, fildll/fistpll is supposed to round-trip a 64-bit integer losslessly, so this really shouldn't corrupt anything. The corruption we are seeing (top 53 bits preserved, bottom 11 bits corrupted) fits with a floating point value and a 53 bit mantissa. So, this is plausibly not even a gcc bug! Could this be hardware specific!!? But this stuff is definitely way outside my area of expertise. @uglyoldbob - are you running this on actual silicon? Or is this some kind of emulated environment?
I'm hesitant to do that. We've not had other reports of this problem. If this was a widespread problem I would have expected someone else to have encountered it before now. My suggestion for now is that @uglyoldbob just uses the -DBROKEN_CLANG_ATOMICS workaround. That's kind of why that define is there - to work around broken atomics. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
I am using yocto scarthgap to build a distro for an i586 machine (the original xbox to be specific), and have run into an issue regarding the openssl library. On version 3.5.5 and 3.5.6 I am seeing the same behavior.
touch /tmp/asdf && openssl storeutl file:/tmp/asdfThis results in no store loader found. I am using the stock yocto configuration for openssl without customization.
Beta Was this translation helpful? Give feedback.
All reactions