Skip to content

Commit eb62969

Browse files
Fix memory issues (emscripten-forge#33)
* Refreshin memory view * Fix merge conflicts * Minor fix * fix memory issues * fix memory issues * fix memory issues * minor fix of cleaning * Fix cleaning memory * Fix conflicts * Cleaning code, replace error_message pointer --------- Co-authored-by: martinRenou <[email protected]>
1 parent 8b3a89d commit eb62969

File tree

5 files changed

+53
-30
lines changed

5 files changed

+53
-30
lines changed

build_wasm.sh

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ emcc unpack.c -o $WASM_LIB/unpack.js \
8484
$CPPFLAGS $LDFLAGS \
8585
${PREFIX}/lib/libarchive.a \
8686
${PREFIX}/lib/libz.a ${PREFIX}/lib/libbz2.a ${PREFIX}/lib/libzstd.a ${PREFIX}/lib/libiconv.a\
87-
-s MODULARIZE=1 -s WASM=1 -O3 -s ALLOW_MEMORY_GROWTH=1 \
87+
-s MODULARIZE=1 -s WASM=1 -O3 -s ALLOW_MEMORY_GROWTH=1 -fsanitize=address \
88+
-s INITIAL_MEMORY=128MB \
8889
-s ENVIRONMENT=web \
89-
-s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap", "getValue", "UTF8ToString"]' \
90-
-s EXPORTED_FUNCTIONS="['_extract_archive', '_malloc', '_free']"
90+
-s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap", "getValue", "UTF8ToString", "wasmMemory"]' \
91+
-s EXPORTED_FUNCTIONS="['_extract_archive', '_free_extracted_archive', '_malloc', '_free']"
9192

9293
echo "Build completed successfully!"

src/index.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@ const fetchByteArray = async (url: string): Promise<Uint8Array> => {
1313
export const initUntarJS = async (): Promise<IUnpackJSAPI> => {
1414
const wasmModule = await initializeWasm();
1515

16-
const extractData = (data: Uint8Array): FilesData => {
16+
const extractData = async (data: Uint8Array): Promise<FilesData> => {
1717
/**Since WebAssembly, memory is accessed using pointers
1818
and the first parameter of extract_archive method from unpack.c, which is Uint8Array of file data, should be a pointer
1919
so we have to allocate memory for file data
2020
**/
21-
const inputPtr = wasmModule._malloc(data.length);
21+
let inputPtr: number | null = wasmModule._malloc(data.length);
2222
wasmModule.HEAPU8.set(data, inputPtr);
2323

2424
// fileCountPtr is the pointer to 4 bytes of memory in WebAssembly's heap that holds fileCount value from the ExtractedArchive structure in unpack.c.
25-
const fileCountPtr = wasmModule._malloc(4);
25+
let fileCountPtr: number | null = wasmModule._malloc(4);
2626

27-
const resultPtr = wasmModule._extract_archive(
27+
let resultPtr: number | null = wasmModule._extract_archive(
2828
inputPtr,
2929
data.length,
3030
fileCountPtr
@@ -49,8 +49,8 @@ export const initUntarJS = async (): Promise<IUnpackJSAPI> => {
4949
and in order to get pointer of statusPtr we need to calculate it as: 0(offset of file pointer) + 4 (offset of fileCount) + 4 (offset for status)
5050
'status' field and pointer of `error_message` are 32-bit signed integer
5151
*/
52-
const statusPtr = wasmModule.getValue(resultPtr + 8, 'i32');
53-
const errorMessagePtr = wasmModule.getValue(resultPtr + 12, 'i32');
52+
let statusPtr: number | null = wasmModule.getValue(resultPtr + 8, 'i32');
53+
let errorMessagePtr: number | null = resultPtr + 12;
5454
if (statusPtr !== 1) {
5555
const errorMessage = wasmModule.UTF8ToString(errorMessagePtr);
5656
console.error(
@@ -59,7 +59,14 @@ export const initUntarJS = async (): Promise<IUnpackJSAPI> => {
5959
'Error:',
6060
errorMessage
6161
);
62-
return {};
62+
wasmModule._free(inputPtr);
63+
wasmModule._free(fileCountPtr);
64+
wasmModule._free_extracted_archive(resultPtr);
65+
inputPtr = null;
66+
fileCountPtr = null;
67+
resultPtr = null;
68+
errorMessagePtr = null;
69+
throw new Error(errorMessage);
6370
}
6471
const filesPtr = wasmModule.getValue(resultPtr, 'i32');
6572
const fileCount = wasmModule.getValue(resultPtr + 4, 'i32');
@@ -95,15 +102,19 @@ export const initUntarJS = async (): Promise<IUnpackJSAPI> => {
95102
dataPtr,
96103
dataSize
97104
);
105+
106+
const fileDataCopy = fileData.slice(0);
98107

99-
files[filename] = fileData;
108+
files[filename] = fileDataCopy;
100109
}
101-
110+
102111
wasmModule._free(inputPtr);
103112
wasmModule._free(fileCountPtr);
104-
wasmModule._free(errorMessagePtr);
105-
wasmModule._free(resultPtr);
106-
113+
wasmModule._free_extracted_archive(resultPtr);
114+
inputPtr = null;
115+
fileCountPtr = null;
116+
resultPtr = null;
117+
errorMessagePtr = null;
107118
return files;
108119
};
109120

src/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
export type FilesData = {[filename: string]: Uint8Array};
1+
export type FilesData = { [filename: string]: Uint8Array };
22

33
export interface IUnpackJSAPI {
4-
extractData: (data: Uint8Array) => FilesData;
4+
extractData: (data: Uint8Array) => Promise<FilesData>;
55
extract: (url: string) => Promise<FilesData>;
66
}

src/unpack.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export interface IWasmModule {
2+
wasmMemory: any;
3+
_free_extracted_archive(resultPtr: number): void;
24
UTF8ToString(filenamePtr: number): string;
35
HEAPU8: Uint8Array;
46
_malloc(size: number): number;

unpack.c

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ typedef struct {
1515
FileData* files;
1616
size_t fileCount;
1717
int status;
18-
char* error_message;
18+
char error_message[256];
1919
} ExtractedArchive;
2020

2121
EMSCRIPTEN_KEEPALIVE
@@ -27,39 +27,37 @@ ExtractedArchive* extract_archive(uint8_t* inputData, size_t inputSize, size_t*
2727

2828
ExtractedArchive* result = (ExtractedArchive*)malloc(sizeof(ExtractedArchive));
2929
if (!result) {
30-
result->status = 0;
31-
result->error_message = strdup("Memory allocation error for ExtractedArchive.");
3230
return NULL;
3331
}
3432

3533
result->files = NULL;
3634
result->fileCount = 0;
3735
result->status = 1;
38-
result->error_message = NULL;
36+
result->error_message[0] = '\0';
3937

4038
archive = archive_read_new();
4139
archive_read_support_filter_all(archive);
4240
archive_read_support_format_all(archive);
4341

4442
if (archive_read_open_memory(archive, inputData, inputSize) != ARCHIVE_OK) {
45-
archive_read_free(archive);
4643
result->status = 0;
47-
result->error_message = strdup(archive_error_string(archive));
44+
snprintf(result->error_message, sizeof(result->error_message), "%s", archive_error_string(archive));
45+
archive_read_free(archive);
4846
return result;
4947
}
5048

5149
while (archive_read_next_header(archive, &entry) == ARCHIVE_OK) {
5250
const char* filename = archive_entry_pathname(entry);
5351
size_t entrySize = archive_entry_size(entry);
5452

55-
files = realloc(files, sizeof(FileData) * (files_count + 1));
53+
54+
files= realloc(files, sizeof(FileData) * (files_count + 1));
5655
if (!files) {
5756
archive_read_free(archive);
5857
result->status = 0;
59-
result->error_message = strdup("Memory allocation error for FileData array.");
58+
snprintf(result->error_message, sizeof(result->error_message), "Memory allocation error for file data.");
6059
return result;
6160
}
62-
6361
files[files_count].filename = strdup(filename);
6462
files[files_count].data = malloc(entrySize);
6563
files[files_count].data_size = entrySize;
@@ -68,7 +66,7 @@ ExtractedArchive* extract_archive(uint8_t* inputData, size_t inputSize, size_t*
6866
free(files[files_count].filename);
6967
archive_read_free(archive);
7068
result->status = 0;
71-
result->error_message = strdup("Memory allocation error for file data.");
69+
snprintf(result->error_message, sizeof(result->error_message), "Memory allocation error for file data.");
7270
return result;
7371
}
7472

@@ -81,9 +79,9 @@ ExtractedArchive* extract_archive(uint8_t* inputData, size_t inputSize, size_t*
8179
free(files[i].data);
8280
}
8381
free(files);
84-
archive_read_free(archive);
8582
result->status = 0;
86-
result->error_message = strdup(archive_error_string(archive));
83+
snprintf(result->error_message, sizeof(result->error_message), "%s", archive_error_string(archive));
84+
archive_read_free(archive);
8785
return result;
8886
}
8987
bytesRead += ret;
@@ -99,4 +97,15 @@ ExtractedArchive* extract_archive(uint8_t* inputData, size_t inputSize, size_t*
9997
}
10098

10199

102-
100+
EMSCRIPTEN_KEEPALIVE
101+
void free_extracted_archive(ExtractedArchive* archive) {
102+
if (!archive) {
103+
fprintf(stderr, "No archive\n");
104+
}
105+
for (size_t i = 0; i < archive->fileCount; i++) {
106+
free(archive->files[i].filename);
107+
free(archive->files[i].data);
108+
}
109+
free(archive->files);
110+
free(archive);
111+
}

0 commit comments

Comments
 (0)