Um ... to me, this looks like a bug. The *names* are in the right order,
but the *values* appear to have been swapped. Or rather, load() just jammed
_ENV as the first upvalue, original order be damned! The documentation for
Returns a string containing a binary representation (a binary chunk)
of the given function, so that a later load on this string returns a
copy of the function (but with new upvalues). If strip is a true
value, the binary representation is created without debug
information about the function (local variable names, lines, etc.).
Functions with upvalues have only their number of upvalues saved. When
(re)loaded, those upvalues receive fresh instances containing nil. (You can
use the debug library to serialize and reload the upvalues of a function in
a way adequate to your needs.)
Well, first off, this is wrong---all but the first upvalue are nil. And if
you receive stripped code, you don't even get the names!  Okay, so it
seems I have to shuffle things around.
Actually the docs are correct for the C API, in which all the upvalues are nil initially. It’s only the Lua load() API family that presets the first upvalue to the supplied environment. As others (and myself) have noted, the load() APIs just assumes that the first upvalue should be the environment, even though that is only true for chunks compiled in their entirety. In addition, as I have noted, the actual upvalue that *does* get _ENV (if there even is one) isn’t guaranteed to be the first.
So far as I can see it’s documented correctly but it’s a bit .. odd. it also leaves a big hole for people trying to sandbox a function, since it gives you a back-door to the global (distinguished) environment regardless of that you do with _ENV if you are not careful to sandbox string.dump and load.