Migrate to IDF 5.5.3 candidate
Pin PlatformIO packages and toolchains, rebase protected SDK overrides, and add WebSocket receive regression coverage. Document isolated candidate validation, archive provenance, and remaining gates.
This commit is contained in:
@@ -41,8 +41,8 @@ def source_path(entry, idf, project=ROOT):
|
||||
|
||||
|
||||
AUXILIARY = {
|
||||
"components/esp_http_server/src/httpd_main.c": "a16ef65069dda13889c67b922f25eb566573983d6c24f01c089a902d5fd26149",
|
||||
"components/esp_http_server/src/httpd_txrx.c": "7659ad52c32f29b9a08208dc8b22d023edf274047835ed58107d82a47ccce00e",
|
||||
"components/esp_http_server/src/httpd_main.c": "55fccf1ec01265dd9be45609c4d8eeb5d9f80da99fee23b2309a6b372c56e24f",
|
||||
"components/esp_http_server/src/httpd_txrx.c": "f0978034ae0acc7e5f5c52fcb4aabc424afd403d433a417e04ff70319a7dd140",
|
||||
}
|
||||
FEATURES = ["MBEDTLS_SSL_PROTO_TLS1_2", "MBEDTLS_SSL_SRV_C",
|
||||
"MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", "MBEDTLS_ECDH_C",
|
||||
@@ -145,8 +145,8 @@ def generator_tests(idf, work):
|
||||
expect_error(lambda: sdk.generate(fake, ROOT, binary), "SHA256 mismatch")
|
||||
assert before == {p: (p.read_bytes(), p.stat().st_mtime_ns) for p in before}
|
||||
shutil.copyfile(idf / TLS_ENTRY.source, last)
|
||||
(fake / version).write_text((fake / version).read_text().replace("VERSION_PATCH 0", "VERSION_PATCH 1"))
|
||||
expect_error(lambda: sdk.generate(fake, ROOT, failed), "5.5.0")
|
||||
(fake / version).write_text((fake / version).read_text().replace("VERSION_PATCH 3", "VERSION_PATCH 1"))
|
||||
expect_error(lambda: sdk.generate(fake, ROOT, failed), "5.5.3")
|
||||
shutil.copyfile(idf / version, fake / version)
|
||||
last.unlink()
|
||||
expect_error(lambda: sdk.generate(fake, ROOT, failed), "No such file")
|
||||
@@ -215,6 +215,44 @@ def extracted_tests(idf, binary, work):
|
||||
"-fsanitize=undefined", "-fsanitize-undefined-trap-on-error"])
|
||||
|
||||
|
||||
def websocket_tests(idf, binary, work):
|
||||
entry = next(e for e in sdk.ENTRIES if e.name == "httpd_ws")
|
||||
text = generated_path(binary, entry).read_text()
|
||||
assert text.encode() == sdk.render_entry(entry, {"idf": idf, "project": ROOT})[1]
|
||||
txrx = (idf / "components/esp_http_server/src/httpd_txrx.c").read_text()
|
||||
assert hashlib.sha256(txrx.encode()).hexdigest() == AUXILIARY["components/esp_http_server/src/httpd_txrx.c"]
|
||||
private = (idf / "components/esp_http_server/src/esp_httpd_priv.h").read_text()
|
||||
options = re.search(r"typedef enum \{[^}]*\} httpd_recv_opt_t;", private)
|
||||
assert options
|
||||
functions = "".join(extract(txrx, n) for n in ("httpd_recv_pending", "httpd_recv_with_opt"))
|
||||
functions += "".join(extract(text, n) for n in (
|
||||
"httpd_ws_check_req", "httpd_ws_unmask_payload", "httpd_ws_recv_frame",
|
||||
"httpd_ws_send_frame", "httpd_ws_get_frame_type"))
|
||||
template = (HERE / "ws.c").read_text().replace("/* SDK_OPTIONS */", options.group())
|
||||
source = template.replace("/* SDK_FUNCTIONS */", functions)
|
||||
flags = ["-fsanitize=undefined", "-fsanitize-undefined-trap-on-error"]
|
||||
compile_run("ws", source, work, flags)
|
||||
# Independently enumerate all five sites, rather than trusting the edit registry.
|
||||
sites = list(re.finditer(r"httpd_recv_with_opt\([^\n]+HTTPD_RECV_OPT_BLOCKING\) < \(int\)sizeof\(([^)]+)\)", functions))
|
||||
assert [m[1] for m in sites] == ["second_byte", "length_bytes", "length_bytes", "aux->mask_key", "first_byte"]
|
||||
for i, match in enumerate(sites):
|
||||
removed = functions[:match.start()] + match[0].replace("(int)sizeof", "sizeof") + functions[match.end():]
|
||||
c = work / f"ws_removed_cast_{i}.c"
|
||||
c.write_text(template.replace("/* SDK_FUNCTIONS */", removed))
|
||||
output = run(["cc", "-std=gnu11", "-Wall", "-Wextra", "-Werror", "-fsyntax-only", c], ok=False)
|
||||
assert "sign-compare" in output, output
|
||||
# Explicit unsigned conversion reproduces the vendor's implicit promotion
|
||||
# without disabling sign-compare diagnostics: rejection must be behavioral.
|
||||
mutant = functions[:match.start()] + "(size_t)" + match[0].replace("(int)sizeof", "sizeof") + functions[match.end():]
|
||||
c = work / f"ws_mutant_{i}.c"
|
||||
exe = work / f"ws_mutant_{i}"
|
||||
c.write_text(template.replace("/* SDK_FUNCTIONS */", mutant))
|
||||
run(["cc", "-std=gnu11", "-O2", "-Wall", "-Wextra", "-Werror", *flags, c, "-o", exe])
|
||||
output = run([exe], ok=False)
|
||||
assert "Assertion" in output or "assertion" in output, output
|
||||
print("WS five removed casts rejected by strict compilation and five unsigned-comparison behavioral mutations rejected PASS")
|
||||
|
||||
|
||||
def compile_run(name, source, work, flags=()):
|
||||
c = work / (name + ".c"); exe = work / name
|
||||
c.write_text("/* Extracted SDK sections retain their upstream Apache-2.0 license. */\n" + source)
|
||||
@@ -410,6 +448,7 @@ def main():
|
||||
work = Path(tmp)
|
||||
binary = generator_tests(idf, work)
|
||||
extracted_tests(idf, binary, work)
|
||||
websocket_tests(idf, binary, work)
|
||||
cmake_fixture_tests(idf, work)
|
||||
extension_fixture_tests(idf, work)
|
||||
if args.build_dir: build_registration(args.build_dir.resolve(), idf)
|
||||
|
||||
Reference in New Issue
Block a user