File 0609-wx-Fix-array-reading-out-of-bounds-and-potential-mem.patch of Package erlang
From b07f98bba732e4bc8e020e3c21b6511ebf909dcf Mon Sep 17 00:00:00 2001
From: Dan Gudmundsson <dgud@erlang.org>
Date: Thu, 6 Nov 2025 16:55:07 +0100
Subject: [PATCH] wx: Fix array reading out of bounds, and potential memory
leaks
Issues reported in the excellent blog post at
https://pvs-studio.com/en/blog/posts/cpp/1305/
---
lib/wx/api_gen/wx_gen_nif.erl | 29 ++++++++++++++++++++++---
lib/wx/c_src/gen/wxe_wrapper_4.cpp | 34 +++++++++++++++---------------
lib/wx/c_src/wxe_gl.cpp | 12 +++++++----
lib/wx/c_src/wxe_return.cpp | 6 +++---
lib/wx/test/wx_class_SUITE.erl | 2 ++
5 files changed, 56 insertions(+), 27 deletions(-)
diff --git a/lib/wx/api_gen/wx_gen_nif.erl b/lib/wx/api_gen/wx_gen_nif.erl
index a77355b5f2..418ef6962f 100644
--- a/lib/wx/api_gen/wx_gen_nif.erl
+++ b/lib/wx/api_gen/wx_gen_nif.erl
@@ -386,6 +386,7 @@ gen_method(CName, M=#method{name=N,params=Ps0,type=T,method_type=MT,id=MethodId
Opts = [Opt || Opt = #param{def=Def,in=In,where=Where} <- Ps2,
Def =/= none, In =/= false, Where =/= c],
decode_options(Opts, Argc),
+
case gen_util:get_hook(c, M#method.pre_hook) of
ignore -> skip;
Pre -> w(" ~s;~n", [Pre])
@@ -540,6 +541,23 @@ decode_opt(#param{name=Name,type=Type}) ->
decode_arguments(Ps0) ->
lists:mapfoldl(fun decode_arg/2,0,Ps0).
+%% Postpone alloc and memcpy until after all Badarg execeptions
+%% so we don't leak memory in case of later badarg
+copy_arguments([#param{where=Where, in=In, def=none, name=N, type=Type}|Rest])
+ when Where =/= erl, Where =/= c, In =/= false ->
+ case Type of
+ #type{base = binary, by_val=copy} ->
+ w(" ~s = (unsigned char *) malloc(~s_bin.size);\n", [N,N]),
+ w(" memcpy(~s,~s_bin.data,~s_bin.size);\n", [N,N,N]);
+ _ ->
+ ignore
+ end,
+ copy_arguments(Rest);
+copy_arguments([_|Rest]) ->
+ copy_arguments(Rest);
+copy_arguments([]) ->
+ ok.
+
store_free(N) ->
case get(free_args) of
undefined -> put(free_args, [N]);
@@ -708,9 +726,10 @@ decode_arg(N,#type{name=Type,base=binary,mod=Mod0,by_val=Copy},Arg,Argc) ->
w(" ErlNifBinary ~s_bin;~n",[N]),
w(" if(!enif_inspect_binary(env, ~s, &~s_bin)) ~s;~n",[Argc, N, badarg(N)]),
case Copy of
- copy ->
- w(" ~s = (unsigned char *) malloc(~s_bin.size);\n", [N,N]),
- w(" memcpy(~s,~s_bin.data,~s_bin.size);\n", [N,N,N]);
+ copy -> %% postpone see copy_arguments
+ %% w(" ~s = (unsigned char *) malloc(~s_bin.size);\n", [N,N]),
+ %% w(" memcpy(~s,~s_bin.data,~s_bin.size);\n", [N,N,N]);
+ ok;
_ ->
w(" ~s = (~s~s*) ~s_bin.data;~n", [N,Mod,Type,N])
end;
@@ -795,6 +814,8 @@ call_wx(_N,{constructor,_},#type{base={class,RClass}},Ps) ->
false -> RClass
end,
+ copy_arguments(Ps),
+
case [P || #param{type={merged,_}}=P <- Ps] of
[] ->
w(" ~s * Result = new ~s(~s);~n",
@@ -836,6 +857,7 @@ call_wx(_N,{constructor,_},#type{base={class,RClass}},Ps) ->
call_wx(N,{member,_},Type,Ps0) ->
{Beg,End} = return_res(Type),
w(" if(!This) throw wxe_badarg(\"This\");~n",[]),
+ copy_arguments(Ps0),
Ps = filter(Ps0),
case [P || #param{type={merged,_}}=P <- Ps] of
[] ->
@@ -856,6 +878,7 @@ call_wx(N,{member,_},Type,Ps0) ->
call_wx(N,{static,Class},Type,Ps) ->
{Beg,End} = return_res(Type),
#class{parent=Parent} = get({class,Class}),
+ copy_arguments(Ps),
case [P || #param{type={merged,_}}=P <- Ps] of
[] when Parent =:= "static" ->
w(" ~s::~s(~s)~s;~n",[Beg,N,args(fun call_arg/1, ",",filter(Ps)),End]);
diff --git a/lib/wx/c_src/gen/wxe_wrapper_4.cpp b/lib/wx/c_src/gen/wxe_wrapper_4.cpp
index 8ab9faead7..1bc49f4810 100644
--- a/lib/wx/c_src/gen/wxe_wrapper_4.cpp
+++ b/lib/wx/c_src/gen/wxe_wrapper_4.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2022. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2025. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1291,11 +1291,11 @@ void wxImage_new_4(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[2], &data_bin)) Badarg("data");
- data = (unsigned char *) malloc(data_bin.size);
- memcpy(data,data_bin.data,data_bin.size);
unsigned char * alpha;
ErlNifBinary alpha_bin;
if(!enif_inspect_binary(env, argv[3], &alpha_bin)) Badarg("alpha");
+ data = (unsigned char *) malloc(data_bin.size);
+ memcpy(data,data_bin.data,data_bin.size);
alpha = (unsigned char *) malloc(alpha_bin.size);
memcpy(alpha,alpha_bin.data,alpha_bin.size);
wxImage * Result = new EwxImage(width,height,data,alpha);
@@ -1321,11 +1321,11 @@ void wxImage_new_3_3(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[1], &data_bin)) Badarg("data");
- data = (unsigned char *) malloc(data_bin.size);
- memcpy(data,data_bin.data,data_bin.size);
unsigned char * alpha;
ErlNifBinary alpha_bin;
if(!enif_inspect_binary(env, argv[2], &alpha_bin)) Badarg("alpha");
+ data = (unsigned char *) malloc(data_bin.size);
+ memcpy(data,data_bin.data,data_bin.size);
alpha = (unsigned char *) malloc(alpha_bin.size);
memcpy(alpha,alpha_bin.data,alpha_bin.size);
wxImage * Result = new EwxImage(sz,data,alpha);
@@ -1656,9 +1656,9 @@ void wxImage_Create_3_0(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[3], &data_bin)) Badarg("data");
+ if(!This) throw wxe_badarg("This");
data = (unsigned char *) malloc(data_bin.size);
memcpy(data,data_bin.data,data_bin.size);
- if(!This) throw wxe_badarg("This");
bool Result = This->Create(width,height,data);
wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true);
rt.send( rt.make_bool(Result));
@@ -1683,9 +1683,9 @@ void wxImage_Create_2_0(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[2], &data_bin)) Badarg("data");
+ if(!This) throw wxe_badarg("This");
data = (unsigned char *) malloc(data_bin.size);
memcpy(data,data_bin.data,data_bin.size);
- if(!This) throw wxe_badarg("This");
bool Result = This->Create(sz,data);
wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true);
rt.send( rt.make_bool(Result));
@@ -1706,14 +1706,14 @@ void wxImage_Create_4(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[3], &data_bin)) Badarg("data");
- data = (unsigned char *) malloc(data_bin.size);
- memcpy(data,data_bin.data,data_bin.size);
unsigned char * alpha;
ErlNifBinary alpha_bin;
if(!enif_inspect_binary(env, argv[4], &alpha_bin)) Badarg("alpha");
+ if(!This) throw wxe_badarg("This");
+ data = (unsigned char *) malloc(data_bin.size);
+ memcpy(data,data_bin.data,data_bin.size);
alpha = (unsigned char *) malloc(alpha_bin.size);
memcpy(alpha,alpha_bin.data,alpha_bin.size);
- if(!This) throw wxe_badarg("This");
bool Result = This->Create(width,height,data,alpha);
wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true);
rt.send( rt.make_bool(Result));
@@ -1738,14 +1738,14 @@ void wxImage_Create_3_2(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[2], &data_bin)) Badarg("data");
- data = (unsigned char *) malloc(data_bin.size);
- memcpy(data,data_bin.data,data_bin.size);
unsigned char * alpha;
ErlNifBinary alpha_bin;
if(!enif_inspect_binary(env, argv[3], &alpha_bin)) Badarg("alpha");
+ if(!This) throw wxe_badarg("This");
+ data = (unsigned char *) malloc(data_bin.size);
+ memcpy(data,data_bin.data,data_bin.size);
alpha = (unsigned char *) malloc(alpha_bin.size);
memcpy(alpha,alpha_bin.data,alpha_bin.size);
- if(!This) throw wxe_badarg("This");
bool Result = This->Create(sz,data,alpha);
wxeReturn rt = wxeReturn(memenv, Ecmd.caller, true);
rt.send( rt.make_bool(Result));
@@ -2673,9 +2673,9 @@ void wxImage_SetAlpha_1(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * alpha;
ErlNifBinary alpha_bin;
if(!enif_inspect_binary(env, argv[1], &alpha_bin)) Badarg("alpha");
+ if(!This) throw wxe_badarg("This");
alpha = (unsigned char *) malloc(alpha_bin.size);
memcpy(alpha,alpha_bin.data,alpha_bin.size);
- if(!This) throw wxe_badarg("This");
This->SetAlpha(alpha);
}
@@ -2708,9 +2708,9 @@ void wxImage_SetData_1(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[1], &data_bin)) Badarg("data");
+ if(!This) throw wxe_badarg("This");
data = (unsigned char *) malloc(data_bin.size);
memcpy(data,data_bin.data,data_bin.size);
- if(!This) throw wxe_badarg("This");
This->SetData(data);
}
@@ -2725,13 +2725,13 @@ void wxImage_SetData_3(WxeApp *app, wxeMemEnv *memenv, wxeCommand& Ecmd)
unsigned char * data;
ErlNifBinary data_bin;
if(!enif_inspect_binary(env, argv[1], &data_bin)) Badarg("data");
- data = (unsigned char *) malloc(data_bin.size);
- memcpy(data,data_bin.data,data_bin.size);
int new_width;
if(!enif_get_int(env, argv[2], &new_width)) Badarg("new_width"); // int
int new_height;
if(!enif_get_int(env, argv[3], &new_height)) Badarg("new_height"); // int
if(!This) throw wxe_badarg("This");
+ data = (unsigned char *) malloc(data_bin.size);
+ memcpy(data,data_bin.data,data_bin.size);
This->SetData(data,new_width,new_height);
}
diff --git a/lib/wx/c_src/wxe_gl.cpp b/lib/wx/c_src/wxe_gl.cpp
index e2327cfb54..babd562be9 100644
--- a/lib/wx/c_src/wxe_gl.cpp
+++ b/lib/wx/c_src/wxe_gl.cpp
@@ -73,15 +73,19 @@ void setActiveGL(wxeMemEnv *memenv, ErlNifPid caller, wxGLCanvas *canvas, wxGLCo
{
ErlNifUInt64 callId = wxe_make_hash(memenv->tmp_env, &caller);
wxe_glc * entry = glc[callId];
+
gl_active_index = callId;
gl_active_pid = caller;
if(!entry) {
- entry = (wxe_glc *) malloc(sizeof(wxe_glc));
- entry->canvas = NULL;
- entry->context = NULL;
+ if(canvas && context) {
+ entry = (wxe_glc *) malloc(sizeof(wxe_glc));
+ entry->canvas = NULL;
+ entry->context = NULL;
+ }
+ else // canvas or context are NULL ignore
+ return;
}
-
if(entry->canvas == canvas && entry->context == context)
return;
diff --git a/lib/wx/c_src/wxe_return.cpp b/lib/wx/c_src/wxe_return.cpp
index 8728dafcf9..49817fa689 100644
--- a/lib/wx/c_src/wxe_return.cpp
+++ b/lib/wx/c_src/wxe_return.cpp
@@ -231,7 +231,7 @@ ERL_NIF_TERM wxeReturn::make_array_objs(wxAuiPaneInfoArray& arr, WxeApp *app, co
ERL_NIF_TERM head, tail;
ERL_NIF_TERM class_name = enif_make_atom(env, cname);
tail = enif_make_list(env, 0);
- for(unsigned int i = arr.GetCount() -1; i >= 0; i--) {
+ for(ErlNifSInt64 i = arr.GetCount() -1; i >= 0; i--) {
head = make_ref(app->getRef((void *) &arr.Item(i),memenv), class_name);
tail = enif_make_list_cell(env, head, tail);
}
@@ -243,7 +243,7 @@ ERL_NIF_TERM wxeReturn::make_array_objs(wxArrayTreeItemIds& arr)
{
ERL_NIF_TERM head, tail;
tail = enif_make_list(env, 0);
- for(unsigned int i = arr.GetCount() -1; i >= 0; i--) {
+ for(ErlNifSInt64 i = arr.GetCount() -1; i >= 0; i--) {
head = make((wxUIntPtr *) arr[i].m_pItem);
tail = enif_make_list_cell(env, head, tail);
}
@@ -255,7 +255,7 @@ ERL_NIF_TERM wxeReturn::make_array_objs(wxGridCellCoordsArray& arr)
{
ERL_NIF_TERM head, tail;
tail = enif_make_list(env, 0);
- for(unsigned int i = arr.GetCount() -1; i >= 0; i--) {
+ for(ErlNifSInt64 i = arr.GetCount() -1; i >= 0; i--) {
head = make(arr[i]);
tail = enif_make_list_cell(env, head, tail);
}
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 5275defce6..2a303a3bee 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -148,6 +148,8 @@ treeCtrl(Config) ->
?m({0, _}, wxTreeCtrl:hitTest(Tree, {X0+W0+W0, Y0+H0+4*H0})),
?m(false, wxTreeCtrl:isTreeItemIdOk(0)),
+ {0, []} = wxTreeCtrl:getSelections(Tree),
+
wxFrame:connect(Tree, command_tree_item_expanded),
wxFrame:connect(Tree, command_tree_item_collapsed),
wxFrame:connect(Frame, close_window),
--
2.51.0