Feed aggregator
SCOTUS Pauses EPA Plan To Keep Smog From Drifting Across State Lines
Read more of this story at Slashdot.
Coinbase Is Suing the SEC and FDIC Over Public Records
Read more of this story at Slashdot.
AI Dataset Licensing Companies Form Sector's First Trade Group
Read more of this story at Slashdot.
Phosphate In NASA's OSIRIS-REx Asteroid Sample Suggests Ocean World Origins
Read more of this story at Slashdot.
SpaceX Scores $843 Million NASA Contract To De-Orbit ISS In 2030
Read more of this story at Slashdot.
CodeSOD: A Stack of XML
Alice works with an XML-based RPC system. They send requests, it does a thing, and returns back a response, all surrounded in XML. The service sending the requests, however, doesn't use a well-established parsing library. The result is that, well, the code ends up here.
First, though, a bit about the data they expect to parse. It's verbose, but fairly straightforward:
<methodResponse> <params> <param> <value> <struct> <member> <name>foo</name> <value> <string>abcde</string> </value> </member> <member> <name>bar</name> <value> <int>12345</int> </value> </member> </struct> </value> </param> </params> </methodResponse>The tree is awkward, but the response contains params, where each param may contain a struct, the struct may contain members, which have a name and a value, where the value contains the actual data, wrapped in a type.
But there's one thing missing here: the service which sends this response recently changed its API, and for some fields, includes an empty <data/> tag, instead of a value. This particular client doesn't care about data fields, and should be able to safely ignore them if they exist.
Now, you might think, "well, that should be easy then," and you'd be right if you were just using a generic XML parser. They didn't do that. They hand-rolled a parser that is specific to this data format. So let's see what happened:
void XmlRpcResponseParser::OnStartElement(const XML_Char *pszName, const XML_Char **papszAttrs) { const string element = pszName; // Sanity if (_states.empty()) { if (element != "methodResponse" && !_get_method_response) { throw "Invalid top-level element <" + element + "> expecting <methodResponse>"; } _got_method_response = true; _states.push(&response); } if (element == "fault") { // response is faulty: just extract error's code and description is_fault = true; } else if (!is_fault && element == "struct") { top()->type = XML_RPC_STRUCT; } else if (!is_fault && element == "array") { top()->type = XML_RPC_ARRAY; } else if (!is_fault && (element == "data" || element == "value")) { if (top()->type == XML_RPC_ARRAY) { top()->xml_array.push_back(Entry()); _states.push(&top()->xml_array.back()); // <------------ #1 } } _cdata.clear(); }Here, they track a stack, so they can keep track of where they are in parsing. Oh, except they don't. They only push onto the stack when they encounter a data or a value element. When the response only contained values, this worked fine. So for years, it sat like this.
But when they added data tags, it stopped working, specifically because of how they handle closing tags:
void XmlRpcResponseParser::OnEndElement(const XML_Char *pszName) { const string element = pszName; if (element == "int" || element == "i4") { top()->integer = atoi(chomp(_cdata).c_str()); top()->type = XML_RPC_INTEGER; } else if (element == "string") { top()->str = _cdata; top()->type = XML_RPC_STRING; } else if (element == "boolean") { const string value = chomp(_cdata); top()->boolean = (value == "1" || value == "true"); top()->type = XML_RPC_BOOLEAN; } else if (!is_fault && element == "name") { _states.push(&top()->xml_struct[_cdata]); } else if (!is_fault && element == "value") { if (!_states.empty()) { _states.pop(); // <------------- #2 } } _cdata.clear(); }Note here that they only pop when they encounter a value element. Which means when they encounter a data element, they push the stack, but never pop it, which gets the whole tree desynced and breaks parsing.
Since this was discovered, most of the service calls have been migrated to use JSON instead of XML. That "solves" the problem, given that the XML parser is broken. But the XML parser is still used for some calls, and the result is that the service being invoked is constrained in how it's allowed to change its API- it can't add data fields to certain responses, because this client will break. Everyone hates this, and someday, the XML endpoints will go away. Someday.
.comment { border: none; } [Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!World's First Carbon Tax On Livestock Will Cost Farmers $100 Per Cow
Read more of this story at Slashdot.
Microsoft Blamed For Million-Plus Patient Record Theft At US Hospital Giant
Read more of this story at Slashdot.
Apple Pauses Work On Planned North Carolina Campus
Read more of this story at Slashdot.
Crypto Industry Super PAC Is 33-2 In Primaries, With $100 Million For House and Senate Races
Read more of this story at Slashdot.
A Russian Propaganda Network Is Promoting an AI-Manipulated Biden Video
Read more of this story at Slashdot.
Microsoft's Canceled Xbox Cloud Console Gets Detailed In New Patent
Read more of this story at Slashdot.
Australian Bank Spots Scams via How Users Hold Their Phones
Read more of this story at Slashdot.
Toys 'R' Us Riles Critics With 'First-Ever' AI-Generated Commercial Using Sora
Read more of this story at Slashdot.
Exam Submissions By AI Found To Earn Higher Grades Than Real-Life Students
Read more of this story at Slashdot.
Air Freight Greenhouse Gas Emissions Up 25% Since 2019, Analysis Finds
Read more of this story at Slashdot.
US Mayors Urge Congress To Ditch Broadband Expansion Bill
Read more of this story at Slashdot.
Astronomers Have Found the Earliest and Most Distant Galaxy Yet
Read more of this story at Slashdot.
Rabbit R1 AI Device Exposed by API Key Leak
Read more of this story at Slashdot.
Big Streamers Have Been Cutting Their Original Content Output
Read more of this story at Slashdot.