2017-11-22 70 views
7

jako normalne C++ execl działa prawidłowo (kompilacja z g++ ok.cc -o ok.elf)execl wywala C++ node.js-dodatek

#include <unistd.h> 
int main(){ 
    execl("/usr/bin/python", "/usr/bin/python", nullptr); 
} 

Ale awarii, gdy działa jako node.js C++ zabudowaną

#include <node.h> 
#include <unistd.h> 

namespace bug{ 
    void wtf(const v8::FunctionCallbackInfo<v8::Value>& args){ 
    execl("/usr/bin/python", "/usr/bin/python", nullptr); 
    } 

    void init(v8::Local<v8::Object> exports){ 
    NODE_SET_METHOD(exports, "wtf", bug::wtf); 
    } 
    NODE_MODULE(NODE_GYP_MODULE_NAME, init) 
} 

Crash of node.js extension

węzeł.js v8.9.1
węzeł-gyp v3.6.2
gcc wersja 6.3.0 20170406 (Ubuntu 6.3.0-12ubuntu2)

+0

Tak, wiem, że execl zastępuje reprezentację pamięci procesu. Oryginalnie używam go do odrodzenia procesu potomnego z 'fork()' syscall –

+1

Węzeł nie obsługuje wszystkich Syscall posix. Zobacz ten wątek https://stackoverflow.com/questions/34290403/a-way-to-call-execl-execle-execlp-execv-execvp-or-execvp-from-node-js. Awaria jest oczekiwana, ponieważ używasz czegoś, co nie jest dla ciebie dostępne –

Odpowiedz

1

Węzeł nie obsługuje wszystkich Syscall posix.

zobacz ten wątek

A way to call execl, execle, execlp, execv, execvP or execvp from Node.js

Oczekuje się, że awaria jak używasz czegoś, co nie jest dostępne. Jak wspomniano w powyższym wątku trzeba albo tworzyć własne Exec

index.cc

#include <nan.h> 
#include <fcntl.h> 
#include <unistd.h> 

int doNotCloseStreamsOnExit(int desc) { 
    int flags = fcntl(desc, F_GETFD, 0); 
    if (flags < 0) return flags; 
    flags &= ~FD_CLOEXEC; //clear FD_CLOEXEC bit 
    return fcntl(desc, F_SETFD, flags); 
} 

void copyArray(char* dest[], unsigned int offset, v8::Local<v8::Array> src) { 
    unsigned int length = src->Length(); 
    for (unsigned int i = 0; i < length; i++) { 
    v8::String::Utf8Value arrayElem(Nan::Get(src, i).ToLocalChecked()->ToString()); 
    std::string arrayElemStr (*arrayElem); 
    char* tmp = new char[arrayElemStr.length() +1]; 
    strcpy(tmp, arrayElemStr.c_str()); 
    dest[i + offset] = tmp; 
    } 
} 

void setEnv(v8::Local<v8::Array> src) { 
    unsigned int length = src->Length(); 
    v8::Local<v8::String> keyProp = Nan::New<v8::String>("key").ToLocalChecked(); 
    v8::Local<v8::String> valueProp = Nan::New<v8::String>("value").ToLocalChecked(); 
    for (unsigned int i = 0; i < length; i++) { 
    v8::Local<v8::Object> obj = Nan::Get(src, i).ToLocalChecked()->ToObject(); 

    v8::String::Utf8Value objKey(Nan::Get(obj, keyProp).ToLocalChecked()->ToString()); 
    v8::String::Utf8Value objValue(Nan::Get(obj, valueProp).ToLocalChecked()->ToString()); 

    std::string objKeyStr (*objKey); 
    char *key = const_cast<char*> (objKeyStr.c_str()); 
    std::string objValueStr (*objValue); 
    char *value = const_cast<char*> (objValueStr.c_str()); 

    setenv(key, value, 1); 
    } 
} 

void Method(const Nan::FunctionCallbackInfo<v8::Value>& info) { 
    if (info.Length() < 3) { 
    return; 
    } 
    if (!info[0]->IsString()) { 
    return; 
    } 

    // get command 
    v8::String::Utf8Value val(info[0]->ToString()); 
    std::string str (*val); 
    char *command = const_cast<char*> (str.c_str()); 

    // set env on the current process 
    v8::Local<v8::Array> envArr = v8::Local<v8::Array>::Cast(info[1]); 
    setEnv(envArr); 

    // build args: command, ...args, NULL 
    v8::Local<v8::Array> argsArr = v8::Local<v8::Array>::Cast(info[2]); 
    char* args[argsArr->Length() + 2]; 
    args[0] = command; 
    copyArray(args, 1, argsArr); 
    args[argsArr->Length() + 1] = NULL; 

    // fix stream flags 
    doNotCloseStreamsOnExit(0); //stdin 
    doNotCloseStreamsOnExit(1); //stdout 
    doNotCloseStreamsOnExit(2); //stderr 

    execvp(command, args); 
} 

void Init(v8::Local<v8::Object> exports) { 
    exports->Set(Nan::New("exec").ToLocalChecked(), 
       Nan::New<v8::FunctionTemplate>(Method)->GetFunction()); 
} 

NODE_MODULE(exec, Init) 

index.js

'use strict'; 

var addon = require('bindings')('addon'); 
var path = require('path'); 
var fs = require('fs'); 

module.exports = function(cmd, env, args) { 
    if (!cmd) { 
    throw new Error('Command is required'); 
    } 

    var envArr = Object.keys(env || {}).map(key => { 
    return { 
     key, 
     value: env[key], 
    }; 
    }); 

    addon.exec(cmd, envArr, args || []); 
}; 

PS: Kod pisał z https://github.com/OrKoN/native-exec w Link do skrzynki jest nieaktywny w przyszłości

Kolejna rzecz, która nie powinieneś próbować zrobić, to wykonać coś, co wymaga TTY, w ten sposób dodasz wiele komplikacji. Tak więc uruchomiony python będzie musiał przejąć kontrolę nad twoim TTY.

Powiązane problemy