瀏覽代碼

Fix #2427 (#2428)

* Fix #2427

* Use setarch -R on Linux to fix ASAN crash on WSL2

WSL2 uses high-entropy ASLR which conflicts with ASAN's shadow memory
requirements, causing the ASAN runtime to crash at startup. Running tests
via setarch -R (ADDR_NO_RANDOMIZE) disables ASLR for the test process,
allowing ASAN to initialize correctly.
yhirose 3 月之前
父節點
當前提交
3cedf31d4c
共有 2 個文件被更改,包括 21 次插入4 次删除
  1. 4 2
      test/Makefile
  2. 17 2
      test/test.cc

+ 4 - 2
test/Makefile

@@ -18,6 +18,8 @@ ifneq ($(OS), Windows_NT)
 		OPENSSL_SUPPORT = -DCPPHTTPLIB_OPENSSL_SUPPORT -lssl -lcrypto
 		MBEDTLS_SUPPORT = -DCPPHTTPLIB_MBEDTLS_SUPPORT -lmbedtls -lmbedx509 -lmbedcrypto
 		WOLFSSL_SUPPORT = -DCPPHTTPLIB_WOLFSSL_SUPPORT -lwolfssl
+		# Disable ASLR for ASAN compatibility on WSL2 (high-entropy ASLR conflicts with ASAN shadow memory)
+		SETARCH = setarch $(shell uname -m) -R
 	endif
 endif
 
@@ -59,7 +61,7 @@ STYLE_CHECK_FILES = $(filter-out httplib.h httplib.cc, \
 	$(wildcard example/*.h example/*.cc fuzzing/*.h fuzzing/*.cc *.h *.cc ../httplib.h))
 
 all : test test_split
-	LSAN_OPTIONS=suppressions=lsan_suppressions.txt ./test
+	LSAN_OPTIONS=suppressions=lsan_suppressions.txt $(SETARCH) ./test
 
 SHARDS ?= 4
 
@@ -69,7 +71,7 @@ define run_parallel
 	for i in $$(seq 0 $$(($(SHARDS) - 1))); do \
 	  GTEST_TOTAL_SHARDS=$(SHARDS) GTEST_SHARD_INDEX=$$i \
 	  LSAN_OPTIONS=suppressions=lsan_suppressions.txt \
-	  ./$(1) --gtest_color=yes > $(1)_shard_$$i.log 2>&1 & \
+	  $(SETARCH) ./$(1) --gtest_color=yes > $(1)_shard_$$i.log 2>&1 & \
 	done; \
 	wait; \
 	for i in $$(seq 0 $$(($(SHARDS) - 1))); do \

+ 17 - 2
test/test.cc

@@ -14275,8 +14275,23 @@ static std::thread serve_single_response(std::promise<int> &port_promise,
     auto cli = ::accept(srv, reinterpret_cast<sockaddr *>(&cli_addr), &cli_len);
 
     if (cli != INVALID_SOCKET) {
-      char buf[4096];
-      ::recv(cli, buf, sizeof(buf), 0);
+      // Read the complete HTTP request (until the blank line that terminates
+      // headers) before sending the response.  If the server closes the socket
+      // while the client's request data is still unread in the kernel receive
+      // buffer, the TCP stack sends RST instead of FIN.  That RST resets the
+      // connection on both sides: it discards the client's receive buffer
+      // (which already holds our response) and causes any in-progress write on
+      // the client to fail with ECONNRESET.  Reading all request data first
+      // ensures close() emits a graceful FIN.
+      {
+        char rbuf[256];
+        std::string req;
+        while (req.find("\r\n\r\n") == std::string::npos) {
+          auto n = ::recv(cli, rbuf, sizeof(rbuf), 0);
+          if (n <= 0) { break; }
+          req.append(rbuf, static_cast<size_t>(n));
+        }
+      }
 
       ::send(cli,
 #ifdef _WIN32