Fixed incorrect memory access issues. (#109)

This commit is contained in:
Ravin Perera
2020-08-20 15:20:11 +05:30
committed by GitHub
parent eb70d9f308
commit baf5d8b14a
17 changed files with 192 additions and 147 deletions

View File

@@ -34,14 +34,14 @@ async function main() {
// Establish HotPocket connection.
if (!await hpc.connect()) {
console.log('Connection failed.');
exit;
exit();
}
console.log('HotPocket Connected.');
// This will get fired if HP server disconnects unexpectedly.
hpc.on(HotPocketEvents.disconnect, () => {
console.log('Server diconnected');
exit;
exit();
})
// This will get fired when contract sends an output.

View File

@@ -32,14 +32,14 @@ async function main() {
// Establish HotPocket connection.
if (!await hpc.connect()) {
console.log('Connection failed.');
exit;
exit();
}
console.log('HotPocket Connected.');
// This will get fired if HP server disconnects unexpectedly.
hpc.on(HotPocketEvents.disconnect, () => {
console.log('Server diconnected');
exit;
console.log('Server disconnected');
exit();
})
// This will get fired when contract sends an output.

View File

@@ -11,8 +11,8 @@ namespace corebill
*/
struct violation_stat
{
uint32_t counter;
uint64_t timestamp;
uint32_t counter = 0;
uint64_t timestamp = 0;
};
void report_violation(const std::string host);

View File

@@ -79,22 +79,15 @@ namespace comm
// Counter to track when to initiate outbound client connections.
int16_t loop_counter = -1;
// Indicates whether at least some bytes were read from any of the clients during the previous iteration.
// If no bytes were read, we would force thread sleep to wait for bytes to arrive.
bool bytes_read = false;
while (true)
{
if (should_stop_listening)
break;
// Prepare poll fd list.
const size_t fd_count = sessions.size() + 1; //+1 for the inclusion of accept_fd
pollfd pollfds[fd_count];
if (poll_fds(pollfds, accept_fd, sessions) == -1)
{
util::sleep(10);
continue;
}
util::sleep(10);
// Accept any new incoming connection if available.
check_for_new_connection(sessions, accept_fd, session_type, is_binary, metric_thresholds);
@@ -109,9 +102,27 @@ namespace comm
loop_counter++;
}
const size_t sessions_count = sessions.size();
// Prepare poll fd list.
const size_t fd_count = sessions.size() + 1; //+1 for the inclusion of accept_fd
pollfd pollfds[fd_count];
memset(pollfds, 0, sizeof(pollfd) * fd_count);
if (poll_fds(pollfds, accept_fd, sessions) == -1)
{
util::sleep(10);
continue;
}
if (!bytes_read)
util::sleep(10);
bytes_read = false;
// Loop through all session fds and read any data.
const size_t sessions_count = sessions.size();
if (sessions_count == 0)
continue;
// Loop through all fds and read any data.
for (size_t i = 1; i <= sessions_count; i++)
{
const short result = pollfds[i].revents;
@@ -126,7 +137,18 @@ namespace comm
if (!should_disconnect)
{
if (result & POLLIN)
should_disconnect = (session.attempt_read(max_msg_size) == -1);
{
const int read_result = session.attempt_read(max_msg_size);
// read_result -1 means error and we should disconnect the client.
// read_result 0 means no bytes were read.
// read_result 1 means some bytes were read.
// read_result 2 means full message were read and processed successfully.
if (read_result > 0)
bytes_read = true;
else if (read_result == -1)
should_disconnect = true;
}
if (result & (POLLERR | POLLHUP | POLLRDHUP | POLLNVAL))
should_disconnect = true;

View File

@@ -12,6 +12,7 @@ namespace comm
constexpr uint32_t INTERVALMS = 60000;
constexpr uint8_t SIZE_HEADER_LEN = 8;
constexpr uint32_t READ_BUFFER_IDLE_SIZE = 64 * 1024;
// Global instances of user and peer session handlers.
usr::user_session_handler user_sess_handler;
@@ -48,8 +49,10 @@ namespace comm
/**
* Attempts to read message data from the given socket fd and passes the message on to the session.
* @param should_disconnect Whether the client fd must be disconnected.
* @param max_msg_size The allowed max byte length of a message to be read.
* @return -1 on error and client must be disconnected. 0 if no message data bytes were read. 1 if some
* bytes were read but a full message is not yet formed. 2 if a fully formed message has been
* read into the read buffer.
*/
int comm_session::attempt_read(const uint64_t max_msg_size)
{
@@ -59,33 +62,39 @@ namespace comm
available_bytes > (max_msg_size + (is_binary ? SIZE_HEADER_LEN : 0))))
return -1;
int res = 0;
// Try to read a complete message using available bytes.
// If complete message is not available silently return.
if (available_bytes > 0)
{
const uint32_t read_len = is_binary ? get_binary_msg_read_len(available_bytes) : available_bytes;
if (read_len == -1)
if (is_binary)
{
return -1;
res = get_binary_msg_read_len(available_bytes);
}
else if (read_len > 0)
else
{
if (!is_binary)
read_buffer.resize(available_bytes);
res = read(read_fd, read_buffer.data(), available_bytes) < available_bytes ? -1 : 2;
}
if (res == 2) // Full message has been read into read buffer.
{
if (on_message(std::string_view(read_buffer.data(), read_buffer.size())) == -1)
res = -1;
// Reset the read buffer.
if (read_buffer.size() > READ_BUFFER_IDLE_SIZE)
{
read_buffer.resize(read_len);
if (read(read_fd, read_buffer.data(), read_len) < read_len)
return -1;
read_buffer.resize(READ_BUFFER_IDLE_SIZE);
read_buffer.shrink_to_fit(); // This is to avaoid large idle memory allocations.
}
int res = on_message(std::string_view(read_buffer.data(), read_len));
read_buffer.clear(); // Clear the buffer after read operation.
read_buffer.clear();
read_buffer_filled_size = 0;
return res;
}
}
return 0;
return res;
}
int comm_session::on_message(std::string_view message)
@@ -168,9 +177,11 @@ namespace comm
/**
* Retrieves the length of the binary message pending to be read. Only relevant for Binary mode.
* @param available_bytes Count of bytes that is available to read from the client socket.
* @return Length of the message if the complete message available to be read. 0 if reading must be skipped. -1 if client must be disconnected.
* @return -1 on error and client must be disconnected. 0 if no message data bytes were read. 1 if some
* bytes were read but a full message is not yet formed. 2 if a fully formed message has been
* read into the read buffer.
*/
uint32_t comm_session::get_binary_msg_read_len(const size_t available_bytes)
int comm_session::get_binary_msg_read_len(const size_t available_bytes)
{
// If we have previously encountered a size header and we are waiting until all message
// bytes are received, we must have the expected message size > 0.
@@ -210,7 +221,8 @@ namespace comm
const size_t read_len = expected_msg_size;
expected_msg_size = 0; // reset the expected msg size.
return read_len;
return 2; // Full message has been read.
}
else
{
@@ -218,11 +230,12 @@ namespace comm
if (read(read_fd, read_buffer.data() + read_buffer_filled_size, data_bytes) == -1)
return -1; // Indicates that we should disconnect the client.
read_buffer_filled_size += data_bytes;
return 1; // Some bytes were read, but full message is not yet formed.
}
}
// Skip reading
return 0;
return 0; // No message data bytes was read.
}
/**

View File

@@ -39,7 +39,7 @@ class comm_session
std::vector<char> read_buffer; // Local buffer to keep collecting data until a complete message can be constructed.
uint32_t read_buffer_filled_size = 0; // How many bytes have been buffered so far.
uint32_t get_binary_msg_read_len(const size_t available_bytes);
int get_binary_msg_read_len(const size_t available_bytes);
int on_message(std::string_view message);
public:

View File

@@ -33,10 +33,10 @@ enum SESSION_THRESHOLDS
*/
struct session_threshold
{
uint64_t threshold_limit;
uint32_t intervalms;
uint64_t counter_value;
uint64_t timestamp;
uint64_t threshold_limit = 0;
uint32_t intervalms = 0;
uint64_t counter_value = 0;
uint64_t timestamp = 0;
session_threshold(const uint64_t threshold_limit, const uint32_t intervalms)
: threshold_limit(threshold_limit), intervalms(intervalms)

View File

@@ -10,114 +10,114 @@
namespace conf
{
constexpr const char *SELF_HOST = "127.0.0.1";
constexpr const char *SELF_HOST = "127.0.0.1";
// Typedef to represent ip address and port pair.
typedef std::pair<std::string, uint16_t> ip_port_pair;
// Typedef to represent ip address and port pair.
typedef std::pair<std::string, uint16_t> ip_port_pair;
// The operating mode of the contract node.
enum OPERATING_MODE
{
OBSERVER = 0, // Observer mode. Only emits NUPs. Does not participate in voting.
PROPOSER = 1 // Consensus participant mode.
};
// The operating mode of the contract node.
enum OPERATING_MODE
{
OBSERVER = 0, // Observer mode. Only emits NUPs. Does not participate in voting.
PROPOSER = 1 // Consensus participant mode.
};
// Holds contextual information about the currently loaded contract.
struct contract_ctx
{
std::string command; // The CLI command issued to launch HotPocket
std::string exe_dir; // Hot Pocket executable dir.
std::string websocketd_exe_path; // Websocketd executable file path.
std::string websocat_exe_path; // Websocketd executable file path.
std::string hpfs_exe_path; // hpfs executable file path.
// Holds contextual information about the currently loaded contract.
struct contract_ctx
{
std::string command; // The CLI command issued to launch HotPocket
std::string exe_dir; // Hot Pocket executable dir.
std::string websocketd_exe_path; // Websocketd executable file path.
std::string websocat_exe_path; // Websocketd executable file path.
std::string hpfs_exe_path; // hpfs executable file path.
std::string contract_dir; // Contract base directory full path
std::string hist_dir; // Contract ledger history dir full path
std::string state_dir; // Contract state maintenence path (hpfs path)
std::string state_rw_dir; // Contract executation read/write state path.
std::string state_read_req_dir; // Contract executation state path for read requests.
std::string log_dir; // Contract log dir full path
std::string config_dir; // Contract config dir full path
std::string config_file; // Full path to the contract config file
std::string tls_key_file; // Full path to the tls secret key file
std::string tls_cert_file; // Full path to the tls certificate
};
std::string contract_dir; // Contract base directory full path
std::string hist_dir; // Contract ledger history dir full path
std::string state_dir; // Contract state maintenence path (hpfs path)
std::string state_rw_dir; // Contract executation read/write state path.
std::string state_read_req_dir; // Contract executation state path for read requests.
std::string log_dir; // Contract log dir full path
std::string config_dir; // Contract config dir full path
std::string config_file; // Full path to the contract config file
std::string tls_key_file; // Full path to the tls secret key file
std::string tls_cert_file; // Full path to the tls certificate
};
// Holds all the contract config values.
struct contract_config
{
// Config elements which are initialized in memory (these are not directly loaded from the config file)
// Holds all the contract config values.
struct contract_config
{
// Config elements which are initialized in memory (these are not directly loaded from the config file)
std::string pubkey; // Contract public key bytes
std::string seckey; // Contract secret key bytes
std::vector<std::string> runtime_binexec_args; // Contract binary execution args used during runtime.
std::vector<std::string> runtime_appbill_args; // Appbill execution args used during runtime.
OPERATING_MODE current_mode; // Current operating mode of the contract (Observer/Proposer)
std::string pubkey; // Contract public key bytes
std::string seckey; // Contract secret key bytes
std::vector<std::string> runtime_binexec_args; // Contract binary execution args used during runtime.
std::vector<std::string> runtime_appbill_args; // Appbill execution args used during runtime.
OPERATING_MODE current_mode = OPERATING_MODE::OBSERVER; // Current operating mode of the contract (Observer/Proposer)
// Config elements which are loaded from the config file.
// Config elements which are loaded from the config file.
OPERATING_MODE startup_mode; // Configured startup operating mode of the contract (Observer/Proposer).
std::string pubkeyhex; // Contract hex public key
std::string seckeyhex; // Contract hex secret key
std::string binary; // Full path to the contract binary
std::string binargs; // CLI arguments to pass to the contract binary
std::string appbill; // binary to execute for appbill
std::string appbillargs; // any arguments to supply to appbill binary by default
std::set<ip_port_pair> peers; // Set of peers keyed by "<ip address>:<port>" concatenated format
std::unordered_set<std::string> unl;// Unique node list (list of binary public keys)
uint16_t peerport; // Listening port for peer connections
uint16_t roundtime; // Consensus round time in ms
uint16_t pubport; // Listening port for public user connections
uint64_t pubmaxsize; // User message max size in bytes
uint64_t pubmaxcpm; // User message rate (characters(bytes) per minute)
uint64_t pubmaxbadmpm; // User bad messages per minute
uint16_t pubmaxcons; // Max inbound user connections
uint64_t peermaxsize; // Peer message max size in bytes
uint64_t peermaxcpm; // Peer message rate (characters(bytes) per minute)
uint64_t peermaxdupmpm; // Peer max duplicate messages per minute
uint64_t peermaxbadmpm; // Peer bad messages per minute
uint64_t peermaxbadsigpm; // Peer bad signatures per minute
uint16_t peermaxcons; // Max inbound peer connections
OPERATING_MODE startup_mode = OPERATING_MODE::OBSERVER; // Configured startup operating mode of the contract (Observer/Proposer).
std::string pubkeyhex; // Contract hex public key
std::string seckeyhex; // Contract hex secret key
std::string binary; // Full path to the contract binary
std::string binargs; // CLI arguments to pass to the contract binary
std::string appbill; // binary to execute for appbill
std::string appbillargs; // any arguments to supply to appbill binary by default
std::set<ip_port_pair> peers; // Set of peers keyed by "<ip address>:<port>" concatenated format
std::unordered_set<std::string> unl; // Unique node list (list of binary public keys)
uint16_t peerport = 0; // Listening port for peer connections
uint16_t roundtime = 0; // Consensus round time in ms
uint16_t pubport = 0; // Listening port for public user connections
std::string loglevel; // Log severity level (debug, info, warn, error)
std::unordered_set<std::string> loggers; // List of enabled loggers (console, file)
};
uint64_t pubmaxsize = 0; // User message max size in bytes
uint64_t pubmaxcpm = 0; // User message rate (characters(bytes) per minute)
uint64_t pubmaxbadmpm = 0; // User bad messages per minute
uint16_t pubmaxcons = 0; // Max inbound user connections
// Global contract context struct exposed to the application.
// Other modeuls will access context values via this.
extern contract_ctx ctx;
uint64_t peermaxsize = 0; // Peer message max size in bytes
uint64_t peermaxcpm = 0; // Peer message rate (characters(bytes) per minute)
uint64_t peermaxdupmpm = 0; // Peer max duplicate messages per minute
uint64_t peermaxbadmpm = 0; // Peer bad messages per minute
uint64_t peermaxbadsigpm = 0; // Peer bad signatures per minute
uint16_t peermaxcons = 0; // Max inbound peer connections
// Global configuration struct exposed to the application.
// Other modeuls will access config values via this.
extern contract_config cfg;
std::string loglevel; // Log severity level (debug, info, warn, error)
std::unordered_set<std::string> loggers; // List of enabled loggers (console, file)
};
int init();
// Global contract context struct exposed to the application.
// Other modeuls will access context values via this.
extern contract_ctx ctx;
int rekey();
// Global configuration struct exposed to the application.
// Other modeuls will access config values via this.
extern contract_config cfg;
int create_contract();
int init();
void set_contract_dir_paths(std::string exepath, std::string basedir);
int rekey();
//------Internal-use functions for this namespace.
int create_contract();
int load_config();
void set_contract_dir_paths(std::string exepath, std::string basedir);
int save_config();
//------Internal-use functions for this namespace.
int validate_config();
int load_config();
int validate_contract_dir_paths();
int save_config();
int is_schema_valid(const rapidjson::Document &d);
int validate_config();
int binpair_to_hex();
int validate_contract_dir_paths();
int hexpair_to_bin();
int is_schema_valid(const rapidjson::Document &d);
void change_operating_mode(const OPERATING_MODE mode);
int binpair_to_hex();
int hexpair_to_bin();
void change_operating_mode(const OPERATING_MODE mode);
} // namespace conf

View File

@@ -19,7 +19,7 @@ namespace cons
struct candidate_user_input
{
const std::string userpubkey;
const uint64_t maxledgerseqno;
const uint64_t maxledgerseqno = 0;
std::string input;
candidate_user_input(const std::string userpubkey, const std::string input, const uint64_t maxledgerseqno)

View File

@@ -19,7 +19,7 @@ struct ledger_cache_entry
struct ledger_history
{
std::string lcl;
uint64_t led_seq_no;
uint64_t led_seq_no = 0;
std::map<uint64_t, ledger_cache_entry> cache;
};

View File

@@ -18,6 +18,11 @@ namespace hpfs
std::string_view to_string_view() const;
h32 &operator=(std::string_view sv);
bool operator<(const h32 rhs) const;
h32()
{
memset(data, 0, sizeof(data));
}
};
extern h32 h32_empty;

View File

@@ -8,9 +8,14 @@ namespace hpfs
{
struct child_hash_node
{
bool is_file;
bool is_file = false;
char name[256];
h32 hash;
child_hash_node()
{
memset(name, 0, sizeof(name));
}
};
int init();

View File

@@ -16,9 +16,9 @@ namespace p2p
struct proposal
{
std::string pubkey;
uint64_t timestamp;
uint64_t time;
uint8_t stage;
uint64_t timestamp = 0;
uint64_t time = 0;
uint8_t stage = 0;
std::string lcl;
hpfs::h32 state;
std::set<std::string> users;
@@ -61,7 +61,7 @@ namespace p2p
struct history_response
{
std::map<uint64_t, const history_ledger> hist_ledgers;
LEDGER_RESPONSE_ERROR error;
LEDGER_RESPONSE_ERROR error = LEDGER_RESPONSE_ERROR::NONE;
};
// Represents an NPL message sent by a peer.
@@ -76,24 +76,24 @@ namespace p2p
struct state_request
{
std::string parent_path; // The requested file or dir path.
bool is_file; // Whether the path is a file or dir.
int32_t block_id; // Block id of the file if we are requesting for file block. Otherwise -1.
bool is_file = false; // Whether the path is a file or dir.
int32_t block_id = 0; // Block id of the file if we are requesting for file block. Otherwise -1.
hpfs::h32 expected_hash; // The expected hash of the requested result.
};
// Represents state file system entry.
struct state_fs_hash_entry
{
std::string name; // Name of the file/dir.
bool is_file; // Whether this is a file or dir.
hpfs::h32 hash; // Hash of the file or dir.
std::string name; // Name of the file/dir.
bool is_file = false; // Whether this is a file or dir.
hpfs::h32 hash; // Hash of the file or dir.
};
// Represents a file block data resposne.
struct block_response
{
std::string path; // Path of the file.
uint32_t block_id; // Id of the block where the data belongs to.
uint32_t block_id = 0; // Id of the block where the data belongs to.
std::string_view data; // The block data.
hpfs::h32 hash; // Hash of the bloc data.
};

View File

@@ -101,10 +101,10 @@ namespace sc
std::vector<int> hpscfds;
// Holds the contract process id (if currently executing).
pid_t contract_pid;
pid_t contract_pid = 0;
// Holds the hpfs rw process id (if currently executing).
pid_t hpfs_pid;
pid_t hpfs_pid = 0;
// Thread to collect contract outputs while contract is running.
std::thread output_fetcher_thread;

View File

@@ -19,7 +19,7 @@ namespace state_sync
// Represents a queued up state sync operation which needs to be performed.
struct backlog_item
{
BACKLOG_ITEM_TYPE type;
BACKLOG_ITEM_TYPE type = BACKLOG_ITEM_TYPE::DIR;
std::string path;
int32_t block_id = -1; // Only relevant if type=BLOCK
hpfs::h32 expected_hash;

View File

@@ -34,7 +34,7 @@ namespace usr
const comm::comm_session &session;
// The messaging protocol used by this user.
const util::PROTOCOL protocol;
const util::PROTOCOL protocol = util::PROTOCOL::JSON;
/**
* @param session The web socket session the user is connected to.

Binary file not shown.