Allocate memory for message blobs on the heap

Messages can be very large, so we don't really want to allocate them on the
stack. Switch to using the heap for them, and try to clean up some of the
string handling while we're at it.
This commit is contained in:
Richard van der Hoff 2016-12-14 11:43:00 +00:00
parent f6c05be8c5
commit 76610c0a3a
3 changed files with 153 additions and 88 deletions

View file

@ -64,34 +64,50 @@ InboundGroupSession.prototype['create'] = restore_stack(function(session_key) {
InboundGroupSession.prototype['decrypt'] = restore_stack(function( InboundGroupSession.prototype['decrypt'] = restore_stack(function(
message message
) { ) {
var message_array = array_from_string(message); var message_buffer, plaintext_buffer;
var message_buffer = stack(message_array);
try {
message_buffer = malloc(message.length);
Module['writeAsciiToMemory'](message, message_buffer, true);
var max_plaintext_length = inbound_group_session_method( var max_plaintext_length = inbound_group_session_method(
Module['_olm_group_decrypt_max_plaintext_length'] Module['_olm_group_decrypt_max_plaintext_length']
)(this.ptr, message_buffer, message_array.length); )(this.ptr, message_buffer, message.length);
// caculating the length destroys the input buffer.
// So we copy the array to a new buffer // caculating the length destroys the input buffer, so we need to re-copy it.
var message_buffer = stack(message_array); Module['writeAsciiToMemory'](message, message_buffer, true);
var plaintext_buffer = stack(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
var message_index = stack(4); var message_index = stack(4);
var plaintext_length = inbound_group_session_method(Module["_olm_group_decrypt"])(
var plaintext_length = inbound_group_session_method(
Module["_olm_group_decrypt"]
)(
this.ptr, this.ptr,
message_buffer, message_array.length, message_buffer, message.length,
plaintext_buffer, max_plaintext_length, plaintext_buffer, max_plaintext_length,
message_index message_index
); );
// Pointer_stringify requires a null-terminated argument (the optional // UTF8ToString requires a null-terminated argument, so add the
// 'len' argument doesn't work for UTF-8 data). // null terminator.
Module['setValue']( Module['setValue'](
plaintext_buffer+plaintext_length, plaintext_buffer+plaintext_length,
0, "i8" 0, "i8"
); );
return { return {
"plaintext": Pointer_stringify(plaintext_buffer), "plaintext": UTF8ToString(plaintext_buffer),
"message_index": Module['getValue'](message_index, "i32") "message_index": Module['getValue'](message_index, "i32")
} }
} finally {
if (message_buffer !== undefined) {
free(message_buffer);
}
if (plaintext_buffer !== undefined) {
free(plaintext_buffer);
}
}
}); });
InboundGroupSession.prototype['session_id'] = restore_stack(function() { InboundGroupSession.prototype['session_id'] = restore_stack(function() {

View file

@ -63,20 +63,36 @@ OutboundGroupSession.prototype['create'] = restore_stack(function() {
); );
}); });
OutboundGroupSession.prototype['encrypt'] = restore_stack(function(plaintext) { OutboundGroupSession.prototype['encrypt'] = function(plaintext) {
var plaintext_array = array_from_string(plaintext); var plaintext_buffer, message_buffer;
try {
var plaintext_length = Module['lengthBytesUTF8'](plaintext);
var message_length = outbound_group_session_method( var message_length = outbound_group_session_method(
Module['_olm_group_encrypt_message_length'] Module['_olm_group_encrypt_message_length']
)(this.ptr, plaintext_array.length); )(this.ptr, plaintext_length);
var plaintext_buffer = stack(plaintext_array);
var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH); // need to allow space for the terminator (which stringToUTF8 always
// writes), hence + 1.
plaintext_buffer = malloc(plaintext_length + 1);
Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
outbound_group_session_method(Module['_olm_group_encrypt'])( outbound_group_session_method(Module['_olm_group_encrypt'])(
this.ptr, this.ptr,
plaintext_buffer, plaintext_array.length, plaintext_buffer, plaintext_length,
message_buffer, message_length message_buffer, message_length
); );
return Pointer_stringify(message_buffer); return Module['UTF8ToString'](message_buffer);
}); } finally {
if (plaintext_buffer !== undefined) {
free(plaintext_buffer);
}
if (message_buffer !== undefined) {
free(message_buffer);
}
}
};
OutboundGroupSession.prototype['session_id'] = restore_stack(function() { OutboundGroupSession.prototype['session_id'] = restore_stack(function() {
var length = outbound_group_session_method( var length = outbound_group_session_method(

View file

@ -4,9 +4,11 @@ var free = Module['_free'];
var Pointer_stringify = Module['Pointer_stringify']; var Pointer_stringify = Module['Pointer_stringify'];
var OLM_ERROR = Module['_olm_error'](); var OLM_ERROR = Module['_olm_error']();
/* The 'length' argument to Pointer_stringify doesn't work if the input includes /* The 'length' argument to Pointer_stringify doesn't work if the input
* characters >= 128; we therefore need to add a NULL character to all of our * includes characters >= 128, which makes Pointer_stringify unreliable. We
* strings. This acts as a symbolic constant to help show what we're doing. * could use it on strings which are known to be ascii, but that seems
* dangerous. Instead we add a NULL character to all of our strings and just
* use UTF8ToString.
*/ */
var NULL_BYTE_PADDING_LENGTH = 1; var NULL_BYTE_PADDING_LENGTH = 1;
@ -297,59 +299,90 @@ Session.prototype['matches_inbound_from'] = restore_stack(function(
Session.prototype['encrypt'] = restore_stack(function( Session.prototype['encrypt'] = restore_stack(function(
plaintext plaintext
) { ) {
var plaintext_buffer, message_buffer;
try {
var random_length = session_method( var random_length = session_method(
Module['_olm_encrypt_random_length'] Module['_olm_encrypt_random_length']
)(this.ptr); )(this.ptr);
var message_type = session_method( var message_type = session_method(
Module['_olm_encrypt_message_type'] Module['_olm_encrypt_message_type']
)(this.ptr); )(this.ptr);
var plaintext_array = array_from_string(plaintext);
var plaintext_length = Module['lengthBytesUTF8'](plaintext);
var message_length = session_method( var message_length = session_method(
Module['_olm_encrypt_message_length'] Module['_olm_encrypt_message_length']
)(this.ptr, plaintext_array.length); )(this.ptr, plaintext_length);
var random = random_stack(random_length); var random = random_stack(random_length);
var plaintext_buffer = stack(plaintext_array);
var message_buffer = stack(message_length + NULL_BYTE_PADDING_LENGTH); // need to allow space for the terminator (which stringToUTF8 always
// writes), hence + 1.
plaintext_buffer = malloc(plaintext_length + 1);
Module['stringToUTF8'](plaintext, plaintext_buffer, plaintext_length + 1);
message_buffer = malloc(message_length + NULL_BYTE_PADDING_LENGTH);
session_method(Module['_olm_encrypt'])( session_method(Module['_olm_encrypt'])(
this.ptr, this.ptr,
plaintext_buffer, plaintext_array.length, plaintext_buffer, plaintext_length,
random, random_length, random, random_length,
message_buffer, message_length message_buffer, message_length
); );
return { return {
"type": message_type, "type": message_type,
"body": Pointer_stringify(message_buffer) "body": Module['UTF8ToString'](message_buffer),
}; };
} finally {
if (plaintext_buffer !== undefined) {
free(plaintext_buffer);
}
if (message_buffer !== undefined) {
free(message_buffer);
}
}
}); });
Session.prototype['decrypt'] = restore_stack(function( Session.prototype['decrypt'] = restore_stack(function(
message_type, message message_type, message
) { ) {
var message_array = array_from_string(message); var message_buffer, plaintext_buffer;
var message_buffer = stack(message_array);
try {
message_buffer = malloc(message.length);
Module['writeAsciiToMemory'](message, message_buffer, true);
var max_plaintext_length = session_method( var max_plaintext_length = session_method(
Module['_olm_decrypt_max_plaintext_length'] Module['_olm_decrypt_max_plaintext_length']
)(this.ptr, message_type, message_buffer, message_array.length); )(this.ptr, message_type, message_buffer, message.length);
// caculating the length destroys the input buffer.
// So we copy the array to a new buffer // caculating the length destroys the input buffer, so we need to re-copy it.
var message_buffer = stack(message_array); Module['writeAsciiToMemory'](message, message_buffer, true);
var plaintext_buffer = stack(
max_plaintext_length + NULL_BYTE_PADDING_LENGTH plaintext_buffer = malloc(max_plaintext_length + NULL_BYTE_PADDING_LENGTH);
);
var plaintext_length = session_method(Module["_olm_decrypt"])( var plaintext_length = session_method(Module["_olm_decrypt"])(
this.ptr, message_type, this.ptr, message_type,
message_buffer, message.length, message_buffer, message.length,
plaintext_buffer, max_plaintext_length plaintext_buffer, max_plaintext_length
); );
// Pointer_stringify requires a null-terminated argument (the optional // UTF8ToString requires a null-terminated argument, so add the
// 'len' argument doesn't work for UTF-8 data). // null terminator.
Module['setValue']( Module['setValue'](
plaintext_buffer+plaintext_length, plaintext_buffer+plaintext_length,
0, "i8" 0, "i8"
); );
return Pointer_stringify(plaintext_buffer); return UTF8ToString(plaintext_buffer);
} finally {
if (message_buffer !== undefined) {
free(message_buffer);
}
if (plaintext_buffer !== undefined) {
free(plaintext_buffer);
}
}
}); });
function Utility() { function Utility() {