XDR: External Data Representation Standard
Extracted elements (28)
The XDR block unit is four bytes: two bytes would produce alignment problems on many architectures, while eight bytes would inflate encoded data size. Four bytes is a compromise that efficiently supports most architectures while keeping data compact.
Variable-length padding bytes are mandated to be zero so that the same data always encodes identically on all machines, enabling meaningful comparison and checksumming of encoded data.
XDR mandates a single big-endian byte order rather than supporting both orderings, because supporting two orders would require a higher-level protocol to signal which is in use; as a data representation standard (not a protocol) XDR cannot provide that negotiation.
XDR uses implicit typing (no type fields on the wire) rather than explicit typing because data-typing has high cost: it expands data size and requires field interpretation at runtime, yet protocols already know the expected type, making type tags redundant.
XDR fits into the ISO presentation layer and is analogous in purpose to X.409 (ASN.1), but differs in using implicit rather than explicit typing. Protocols such as ONC RPC and NFS use XDR for data formatting.
Decoders must ensure that the incoming size of a variable-length element does not exceed the length of any provisioned receiver buffer, to prevent buffer overflow attacks.
Boolean is a defined enumerated type with FALSE=0 and TRUE=1, encoded as a 32-bit signed integer. It is given an explicit type in the standard due to its frequency of use.
Enumerations have the same wire representation as signed integers (32-bit). It is an error to encode an integer value that has not been assigned in the enum declaration.
Optional-data (type-name *identifier) is syntactic sugar for a discriminated union on a boolean: TRUE arm contains the typed element, FALSE arm is void. It supports recursive data structures such as linked lists and trees.
XDR does not use IANA registration for new data types. New types require a standards-track RFC that updates or obsoletes RFC 4506; they are not registered with IANA.
Buffer overflow risk: protocols should define explicit upper bounds on variable-length fields using the '<value>' notation. Decoders must independently validate that incoming lengths do not exceed allocated buffer sizes.
Embedded NUL octets in XDR strings can cause memory leakage or denial of service when the decoder uses NUL-terminated string semantics, because the apparent string size differs from the allocated buffer size.
Recursive decoder/encoder subroutines processing optional-data linked structures (e.g., struct m { int x; struct m *next; }) can be exploited via long lists to cause stack overflow. Implementations should use non-recursive algorithms or enforce a list-length limit.
Strings may contain ASCII characters that are legal in XDR but illegal for the target application (e.g., '/' in a filename component); decoders must validate application-level string constraints to prevent denial-of-service attacks.
All XDR items are encoded as a multiple of four bytes (32 bits). If n bytes are needed and n is not a multiple of four, 0 to 3 residual zero bytes are appended to reach the next 4-byte boundary.
Discriminated union encodes a 4-byte discriminant (int, unsigned int, bool, or enum) followed by the selected arm's encoding. If no default arm is declared, encoding an unspecified discriminant value is invalid.
Double-precision floating-point (double) is 64 bits encoded per IEEE 754: 1-bit sign, 11-bit biased exponent (bias=1023), and 52-bit mantissa fraction, transmitted big-endian. NaN is system-dependent.
Fixed-length array (type-name identifier[n]) encodes each of the n elements in order; each element's encoding is itself a multiple of four bytes. Elements of the same declared type may vary in encoded size (e.g., variable-length strings).
Fixed-length opaque data (opaque identifier[n]) encodes n raw bytes followed by 0–3 zero padding bytes so the total is a multiple of four. The padding bytes carry no information.
Hyper integer and unsigned hyper integer are 64-bit (8-byte) two's complement values encoded big-endian, with most significant byte at offset 0 and least significant at offset 7.
Quadruple-precision floating-point (quadruple) is 128 bits: 1-bit sign, 15-bit biased exponent (bias=16383), and 112-bit mantissa fraction, analogous to IEEE 754 double-extended precision. NaN is system-dependent.
Single-precision floating-point (float) is 32 bits encoded per IEEE 754: 1-bit sign (S), 8-bit biased exponent (E, bias=127), and 23-bit mantissa fraction (F), transmitted big-endian. NaN is system-dependent and must not be interpreted as anything other than NaN.
String encodes a 4-byte unsigned integer length n followed by n ASCII bytes followed by 0–3 zero padding bytes. The declared maximum m defaults to 2^32-1; encoding a length exceeding the maximum is an error.
Structure encodes its components in declaration order, each a multiple of four bytes; components may differ in size.
Variable-length array (counted array) encodes a 4-byte unsigned integer element count n, followed by each of the n elements in order. Encoding a count greater than the declared maximum m is an error.
Variable-length opaque data encodes a 4-byte unsigned integer length n, followed by n bytes of data, followed by 0–3 zero padding bytes. The maximum length m defaults to 2^32-1 if unspecified; encoding a length exceeding the declared maximum is an error.
XDR signed integer is a 32-bit two's complement value encoding the range [-2147483648, 2147483647], transmitted big-endian with most significant byte first (byte 0) and least significant byte last (byte 3).
XDR unsigned integer is a 32-bit big-endian value encoding the range [0, 4294967295], with most significant byte at offset 0 and least significant at offset 3.