Skip to content

Commit f35cee4

Browse files
committed
fix: fix message and request leaks.
1 parent e312186 commit f35cee4

File tree

7 files changed

+180
-37
lines changed

7 files changed

+180
-37
lines changed

bridge/scripts/code_generator/src/ts_types/dap/generateSource.ts

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ const initializeTypes: {
2222
array: boolean
2323
}
2424
} = {};
25+
const freeTypes: {
26+
[key: string]: {
27+
normal: boolean;
28+
array: boolean
29+
}
30+
} = {};
2531

2632
function generateTypeStringify(object: ClassObject, propName: string, info: DAPInfoCollector, externalInitialize: string[]): void {
2733
if (stringifyTypes[object.name]) return;
@@ -431,6 +437,106 @@ function generateResponseBodyStringifyCode(info: DAPInfoCollector, responses: st
431437
}
432438

433439

440+
function generateTypeFree(object: ClassObject, propType: ParameterType, info: DAPInfoCollector, externalInitialize: string[], isArray?: boolean) {
441+
if (freeTypes[object.name]) {
442+
const type = freeTypes[object.name];
443+
if (isArray) {
444+
if (type.array) {
445+
return;
446+
}
447+
} else {
448+
if (type.normal) return;
449+
}
450+
}
451+
freeTypes[object.name] = {
452+
normal: !isArray,
453+
array: !!isArray
454+
};
455+
let freeCode: string[] = [];
456+
if (object.props) {
457+
object.props.forEach(prop => {
458+
let code = generatePropFree(prop, externalInitialize, info);
459+
if (code) {
460+
freeCode.push(code);
461+
}
462+
});
463+
}
464+
465+
let initCode = '';
466+
467+
if (isArray) {
468+
initCode = `
469+
for(int i = 0; i < length; i ++) {
470+
${freeCode.join('\n')}
471+
}
472+
js_free(ctx, args);
473+
`;
474+
} else {
475+
initCode = `
476+
${freeCode.join('\n')}
477+
js_free(ctx, args);
478+
`;
479+
}
480+
481+
externalInitialize.push(`static ${object.name}* free_property_${getTypeName(propType)}${isArray ? '_1' : ''}(JSContext* ctx, ${object.name}* args${isArray ? ', size_t length' : ''}) {
482+
${initCode}
483+
}`);
484+
}
485+
486+
function generatePropFree(prop: PropsDeclaration, externalInitialize: string[], info: DAPInfoCollector): string | null {
487+
const typeKind = getTypeKind(prop.type);
488+
let callCode = '';
489+
if (typeKind === PropTypeKind.normal || typeKind === PropTypeKind.normalArray) {
490+
let value = prop.type.value;
491+
const isArray = prop.type.isArray;
492+
493+
if (value === FunctionArgumentType.dom_string) {
494+
callCode += `free_property_string${isArray ? '_1' : ''}(ctx, args->${prop.name}${isArray ? `, args->${prop.name}Len` : ''});`
495+
}
496+
} else if (typeKind === PropTypeKind.reference || typeKind === PropTypeKind.referenceArray) {
497+
let targetTypes = Array.from(info.others).find(o => {
498+
return o.name === getTypeName(prop.type)
499+
});
500+
if (targetTypes) {
501+
const isArray = prop.type.isArray;
502+
generateTypeFree(targetTypes, prop.type, info, externalInitialize, isArray);
503+
callCode += `free_property_${getTypeName(prop.type)}${isArray ? '_1' : ''}(ctx, args->${prop.name}${isArray ? `, args->${prop.name}Len` : ''});\n`;
504+
}
505+
}
506+
507+
return callCode;
508+
}
509+
510+
function generateRequestArgumentFreeCode(info: DAPInfoCollector, requests: string[], externalInitialize: string[]) {
511+
return requests.map(request => {
512+
let targetArgument = Array.from(info.arguments).find((ag) => {
513+
const prefix = ag.name.replace('Arguments', '');
514+
return request.indexOf(prefix) >= 0;
515+
});
516+
517+
if (!targetArgument) {
518+
return '';
519+
}
520+
521+
let freeCode: string[] = [];
522+
if (targetArgument.props) {
523+
targetArgument.props.forEach(prop => {
524+
let code = generatePropFree(prop, externalInitialize, info);
525+
if (code) {
526+
freeCode.push(code);
527+
}
528+
});
529+
}
530+
const name = request.replace('Request', '');
531+
return addIndent(`if (strcmp(command, "${_.camelCase(name)}") == 0) {
532+
${name}Arguments* args = (${name}Arguments*) arguments;
533+
${freeCode.join('\n')}
534+
js_free(ctx, args);
535+
}`, 2);
536+
537+
}).join('\n');
538+
}
539+
434540
export function generateDAPSource(info: DAPInfoCollector) {
435541
const requests: string[] = getLists(info.requests);
436542
const events: string[] = getLists(info.events);
@@ -442,6 +548,7 @@ export function generateDAPSource(info: DAPInfoCollector) {
442548
const responseInit = generateResponseInitializer(info, responses, externalInitialize);
443549
const eventBodyStringifyCode = generateEventBodyStringifyCode(info, events, externalInitialize);
444550
const responseBodyStringifyCode = generateResponseBodyStringifyCode(info, responses, externalInitialize);
551+
const freeEventArgument = generateRequestArgumentFreeCode(info, requests, externalInitialize);
445552
return _.template(readConverterTemplate())({
446553
info,
447554
requests,
@@ -450,7 +557,8 @@ export function generateDAPSource(info: DAPInfoCollector) {
450557
responseInit,
451558
eventBodyStringifyCode,
452559
responseBodyStringifyCode,
453-
externalInitialize
560+
externalInitialize,
561+
freeEventArgument
454562
}).split('\n').filter(str => {
455563
return str.trim().length > 0;
456564
}).join('\n');

bridge/scripts/code_generator/templates/dap_templates/dap_converter.c.tpl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Generated from template:
2+
// code_generator/templates/dap_templates/dap_converter.h.tpl
3+
14
/*
25
* Copyright (C) 2022-present The WebF authors. All rights reserved.
36
*/
@@ -49,6 +52,15 @@ static const char** get_property_string_copy_1(JSContext* ctx, JSValue this_obje
4952

5053
return return_value;
5154
}
55+
static void free_property_string(JSContext* ctx, const char* str) {
56+
js_free(ctx, (void*) str);
57+
}
58+
59+
static void free_property_string_1(JSContext* ctx, const char** str, size_t length) {
60+
for(int i = 0; i < length; i ++) {
61+
js_free(ctx, (void*) str[i]);
62+
}
63+
}
5264
static int64_t get_property_int64(JSContext* ctx, JSValue this_object, const char* prop) {
5365
JSValue vp = JS_GetPropertyStr(ctx, this_object, prop);
5466
int64_t v;
@@ -152,4 +164,23 @@ const char* stringify_response(JSContext* ctx, Response* response) {
152164
JS_FreeValue(ctx, object);
153165
return result;
154166
}
167+
168+
static void free_request_arguments(JSContext* ctx, void* arguments, const char* command) {
169+
<%= freeEventArgument %>
170+
}
171+
172+
void free_request(JSContext* ctx, Request* request) {
173+
const char* command = request->command;
174+
free_request_arguments(ctx, request->arguments, command);
175+
js_free(ctx, request);
176+
}
177+
178+
void free_response(JSContext* ctx, Response* response) {
179+
180+
}
181+
182+
void free_event(JSContext* const, Event* event) {
183+
184+
}
185+
155186
#endif

bridge/scripts/code_generator/templates/dap_templates/dap_converter.h.tpl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// Generated from template:
2+
// code_generator/templates/dap_templates/dap_converter.cc.tpl
3+
14
/*
25
* Copyright (C) 2022-present The WebF authors. All rights reserved.
36
*/
@@ -14,5 +17,8 @@ const char* stringify_event(JSContext* ctx, Event* event, size_t* length);
1417
void* initialize_event(JSContext* ctx, const char* type);
1518
void* initialize_response(JSContext* ctx, const Request* corresponding_request, const char* type);
1619
const char* stringify_response(JSContext* ctx, Response* response);
20+
void free_request(JSContext* ctx, Request* request);
21+
void free_response(JSContext* ctx, Response* response);
22+
void free_event(JSContext* ctx, Event* event);
1723

1824
#endif

bridge/scripts/code_generator/templates/dap_templates/dap_protocol.h.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Generated from template:
2+
// code_generator/templates/dap_templates/dap_protocol.h.tpl
13
/*
24
* Copyright (C) 2022-present The WebF authors. All rights reserved.
35
*/

bridge/third_party/quickjs/src/core/dap_protocol.d.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,22 @@ interface StoppedEventBody {
164164
hitBreakpointIds?: number[];
165165
}
166166

167+
interface TerminatedEventBody {
168+
/**
169+
* A debug adapter may set `restart` to true (or to an arbitrary object) to
170+
* request that the client restarts the session.
171+
* The value is not interpreted by the client and passed unmodified as an
172+
* attribute `__restart` to the `launch` and `attach` requests.
173+
*/
174+
restart?: any;
175+
}
176+
177+
interface TerminatedEvent extends Event {
178+
event: 'terminated';
179+
180+
body?: TerminatedEventBody;
181+
}
182+
167183
interface StoppedEvent extends Event {
168184
event: 'stopped';
169185
body: StoppedEventBody;

bridge/third_party/quickjs/src/core/debugger.c

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -199,35 +199,11 @@ static uint32_t write_backend_message(JSDebuggerInfo* info, const char* buffer,
199199
return 1;
200200
}
201201

202-
static uint32_t js_transport_write_fully(JSDebuggerInfo* info, const char* buffer, size_t length) {
203-
return write_backend_message(info, buffer, length);
204-
}
205-
206202
static void js_transport_send_response(JSDebuggerInfo* info, JSContext* ctx, Response* response) {
207203
const char* buf = stringify_response(ctx, (Response*) response);
208204
write_backend_message(info, buf, strlen(buf));
209205
}
210206

211-
static uint32_t js_transport_write_value(JSDebuggerInfo* info, JSValue value) {
212-
JSValue stringified = JS_JSONStringify(info->ctx, value, JS_UNDEFINED, JS_UNDEFINED);
213-
size_t len;
214-
const char* str = JS_ToCStringLen(info->ctx, &len, stringified);
215-
uint32_t ret = 0;
216-
if (len)
217-
ret = js_transport_write_fully(info, str, len);
218-
// else send error somewhere?
219-
JS_FreeCString(info->ctx, str);
220-
JS_FreeValue(info->ctx, stringified);
221-
JS_FreeValue(info->ctx, value);
222-
return ret;
223-
}
224-
225-
static JSValue js_transport_new_envelope(JSDebuggerInfo* info, const char* type) {
226-
JSValue ret = JS_NewObject(info->ctx);
227-
JS_SetPropertyStr(info->ctx, ret, "type", JS_NewString(info->ctx, type));
228-
return ret;
229-
}
230-
231207
static void js_transport_send_event(JSDebuggerInfo* info, Event* event) {
232208
size_t length;
233209
const char* buf = stringify_event(info->ctx, event, &length);
@@ -394,8 +370,7 @@ static void process_request(JSDebuggerInfo* info, struct DebuggerSuspendedState*
394370
response->body->type = variable_type.type;
395371
response->body->variablesReference = variable_type.variablesReference;
396372

397-
const char* buf = stringify_response(ctx, (Response*)response);
398-
write_backend_message(info, buf, strlen(buf));
373+
js_transport_send_response(info, ctx, (Response*) response);
399374

400375
JS_FreeCString(ctx, evaluate_result);
401376
JS_FreeValue(ctx, result);
@@ -639,6 +614,9 @@ static void js_process_debugger_messages(JSDebuggerInfo* info, const uint8_t* cu
639614
Request* request = js_malloc(ctx, sizeof(Request));
640615
parse_request(ctx, request, item.buf, item.length);
641616
process_request(info, &state, request);
617+
free_request(ctx, request);
618+
619+
js_free(ctx, item.buf);
642620
} while (info->is_paused);
643621

644622
done:
@@ -780,8 +758,8 @@ void js_debugger_free(JSRuntime* rt, JSDebuggerInfo* info) {
780758
return;
781759

782760
// don't use the JSContext because it might be in a funky state during teardown.
783-
const char* terminated = "{\"type\":\"event\",\"event\":{\"type\":\"terminated\"}}";
784-
js_transport_write_fully(info, terminated, strlen(terminated));
761+
TerminatedEvent* event = initialize_event(info->ctx, "terminated");
762+
js_transport_send_event(info, (Event*) event);
785763

786764
struct list_head* el;
787765

webf/lib/src/devtools/server.dart

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import 'dart:async';
77
import 'dart:collection';
88
import 'dart:convert';
9-
import 'dart:developer';
109
import 'dart:io';
1110
import 'dart:isolate';
1211
import 'dart:ffi';
@@ -198,13 +197,15 @@ class IsolateInspector {
198197

199198
DartDebuggerReadBackendCommands fn = debuggerMethods.ref.readBackendCommands.asFunction();
200199
if (fn != nullptr) {
201-
Pointer<DebuggerMessageBuffer> buffer = malloc.allocate(sizeOf<DebuggerMessageBuffer>());
202-
int result = fn(debuggerContext, buffer);
200+
Pointer<DebuggerMessageBuffer> message = malloc.allocate(sizeOf<DebuggerMessageBuffer>());
201+
int result = fn(debuggerContext, message);
203202
if (result == 0) {
204-
Timer.run(readDebuggerBackendMessage);
203+
malloc.free(message.ref.buffer);
204+
malloc.free(message);
205+
Timer(Duration(milliseconds: 1), readDebuggerBackendMessage);
205206
return;
206207
}
207-
String str = buffer.ref.buffer.toDartString(length: buffer.ref.length);
208+
String str = message.ref.buffer.toDartString(length: message.ref.length);
208209
print('backend $str');
209210
if (_ws != null) {
210211
if (clientKind == ConnectionClientKind.vscode) {
@@ -213,12 +214,13 @@ class IsolateInspector {
213214
// TODO: Add adaptor from DAP to CDP..
214215
}
215216
} else {
216-
_pendingDebuggerMessages.add(str);
217+
// _pendingDebuggerMessages.add(str);
217218
}
218-
malloc.free(buffer);
219+
malloc.free(message.ref.buffer);
220+
malloc.free(message);
219221
}
220222

221-
Timer.run(readDebuggerBackendMessage);
223+
Timer(Duration(seconds: 1), readDebuggerBackendMessage);
222224
}
223225

224226
void _flushPendingDebuggerMessage() {

0 commit comments

Comments
 (0)