#ifndef ____call_h__ #define ____call_h__ #include "Tag.h" #include namespace jet { class __call : public Tag { public: __call(coreutils::ZString &in, coreutils::MString &parentOut, Global &global, Tag *parent, Tag *local); private: int pid; int status; int ix; int fdi[2]; int fdo[2]; int rc; char *argv[50]; // Owns the actual character storage argv[] points into. Resolved // MStrings used to be created as unnamed temporaries with only // their .c_str() pointer kept (argv[ix] = resolveKeyword(arg) // .c_str()) - the temporary is destroyed at the end of that same // statement, so argv[ix] was a dangling pointer from that point // on, read only much later by execvpe() in the forked child. // Undefined behavior - confirmed via a real repro: two sequential // tags (date, then cp using date's own captured output) // corrupted each other's arguments, producing a "cp" invocation // that actually ran /bin/date with garbage arguments instead. // Reserved to its final size up front (see the constructor) so no // push_back can reallocate and invalidate a c_str() pointer // already stored in argv[] earlier in the same construction. std::vector argStrings; }; } #endif