@@ -1427,3 +1427,48 @@ async def test_issue_5931_malformed_protocol_crash(df_server: DflyInstance):
14271427 client = df_server .client ()
14281428 await client .ping ()
14291429 assert await client .ping () == True
1430+
1431+
1432+ @dfly_args ({})
1433+ async def test_issue_5949_nil_bulk_string_crash (df_server : DflyInstance ):
1434+ """
1435+ Regression test for #5949
1436+
1437+ The crash1.txt and crash2.txt files contain malformed RESP protocol with NIL bulk
1438+ strings ($-1) as command arguments, which caused the server to crash with:
1439+ "Check failed: RespExpr::STRING == arg.type" in FromArgs()
1440+
1441+ According to RESP protocol spec, NIL bulk strings are valid for server responses
1442+ but NOT for command arguments sent by clients. Commands must be arrays of bulk strings.
1443+ """
1444+ # Open raw TCP connection to send malformed protocol
1445+ reader , writer = await asyncio .open_connection ("127.0.0.1" , df_server .port )
1446+
1447+ try :
1448+ # Test crash1.txt: MULTI followed by SET with NIL bulk string argument
1449+ # *1\r\n$5\r\nMULTI\r\n*3\r\n$3\r\nSET\r\n$1\r\na\r\n$-1\r\n1\r\n*1\r\n$4\r\nEXEC\r\n
1450+ crash_data = (
1451+ b"*1\r \n $5\r \n MULTI\r \n *3\r \n $3\r \n SET\r \n $1\r \n a\r \n $-1\r \n 1\r \n *1\r \n $4\r \n EXEC\r \n "
1452+ )
1453+
1454+ writer .write (crash_data )
1455+ await writer .drain ()
1456+
1457+ try :
1458+ response = await asyncio .wait_for (reader .read (1024 ), timeout = 2.0 )
1459+ # If we get a response, it should be an error, not a crash
1460+ except asyncio .TimeoutError :
1461+ # Timeout is acceptable - connection might be closed
1462+ pass
1463+ except ConnectionError :
1464+ # Connection closed is acceptable - server detected bad protocol
1465+ pass
1466+
1467+ finally :
1468+ writer .close ()
1469+ await writer .wait_closed ()
1470+
1471+ # Verify server is still running by making a normal request
1472+ client = df_server .client ()
1473+ await client .ping ()
1474+ assert await client .ping () == True
0 commit comments