2017-11-22 58 views
7

Như C++ bình thường execl hoạt động tốt (biên soạn với g++ ok.cc -o ok.elf)execl treo C++ Node.js-addon

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

Nhưng tai nạn, khi công trình như Node.js C++ addon

#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

node.js v8.9.1
nút-gyp v3.6.2
phiên bản gcc 6.3.0 20170406 (Ubuntu 6.3.0-12ubuntu2)

+0

Vâng tôi biết, execl đó thay thế biểu diễn bộ nhớ quá trình. Ban đầu tôi sử dụng nó để sinh ra quá trình con với 'fork()' syscall –

+1

Node không hỗ trợ tất cả các syscall posix. Xem chủ đề này https://stackoverflow.com/questions/34290403/a-way-to-call-execl-execle-execlp-execv-execvp-or-execvp-from-node-js. Sự cố xảy ra khi bạn đang sử dụng thứ gì đó không có sẵn cho bạn –

Trả lời

1

Nút không hỗ trợ tất cả syscall posix.

Xem chủ đề này

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

Vụ tai nạn được dự kiến ​​như bạn đang sử dụng một cái gì đó mà không có sẵn cho bạn. Như đã thảo luận trong các chủ đề trên, bạn cần phải thể tạo exec của riêng bạn

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: Mã đăng từ https://github.com/OrKoN/native-exec, trong trường hợp liên kết không hoạt động trong tương lai

Ngoài ra một điều khác bạn không nên cố gắng thực hiện một cái gì đó mà cần để có được TTY, bạn sẽ thêm rất nhiều phức tạp trong trường hợp đó. Vì vậy, chạy python sẽ cần phải kiểm soát TTY của bạn.