Skip to content

Commit

Permalink
check thread for 0, and panic, *before* calling pthread_join/WaitForS…
Browse files Browse the repository at this point in the history
…ingleObject too (prevents undefined behaviour on musl)
  • Loading branch information
spytheman committed Jan 15, 2025
1 parent 1764442 commit b4e121f
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 115 deletions.
115 changes: 0 additions & 115 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -1441,121 +1441,6 @@ fn (mut g Gen) write_shareds() {
}
}

fn (mut g Gen) register_thread_void_wait_call() {
lock g.waiter_fns {
if '__v_thread_wait' in g.waiter_fns {
return
}
g.waiter_fns << '__v_thread_wait'
g.waiter_fn_definitions.writeln('void __v_thread_wait(__v_thread thread);')
}
g.gowrappers.writeln('void __v_thread_wait(__v_thread thread) {')
if g.pref.os == .windows {
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread, INFINITE);')
} else {
g.gowrappers.writeln('\tint stat = pthread_join(thread, (void **)NULL);')
}
g.gowrappers.writeln('\tif (stat != 0) { _v_panic(_SLIT("unable to join thread")); }')
if g.pref.os == .windows {
g.gowrappers.writeln('\tCloseHandle(thread);')
}
g.gowrappers.writeln('}')
}

fn (mut g Gen) register_thread_array_wait_call(eltyp string) string {
is_void := eltyp == 'void'
thread_typ := if is_void { '__v_thread' } else { '__v_thread_${eltyp}' }
ret_typ := if is_void { 'void' } else { 'Array_${eltyp}' }
thread_arr_typ := 'Array_${thread_typ}'
fn_name := '${thread_arr_typ}_wait'
mut should_register := false
lock g.waiter_fns {
if fn_name !in g.waiter_fns {
g.waiter_fns << fn_name
should_register = true
}
}
if should_register {
if is_void {
g.register_thread_void_wait_call()
g.waiter_fn_definitions.writeln('void ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
void ${fn_name}(${thread_arr_typ} a) {
for (int i = 0; i < a.len; ++i) {
${thread_typ} t = ((${thread_typ}*)a.data)[i];
if (t == 0) continue;
__v_thread_wait(t);
}
}')
} else {
g.waiter_fn_definitions.writeln('${ret_typ} ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
${ret_typ} ${fn_name}(${thread_arr_typ} a) {
${ret_typ} res = __new_array_with_default(a.len, a.len, sizeof(${eltyp}), 0);
for (int i = 0; i < a.len; ++i) {
${thread_typ} t = ((${thread_typ}*)a.data)[i];')
if g.pref.os == .windows {
g.gowrappers.writeln('\t\tif (t.handle == 0) continue;')
} else {
g.gowrappers.writeln('\t\tif (t == 0) continue;')
}
g.gowrappers.writeln('\t\t((${eltyp}*)res.data)[i] = __v_thread_${eltyp}_wait(t);
}
return res;
}')
}
}
return fn_name
}

fn (mut g Gen) register_thread_fixed_array_wait_call(node ast.CallExpr, eltyp string) string {
is_void := eltyp == 'void'
thread_typ := if is_void { '__v_thread' } else { '__v_thread_${eltyp}' }
ret_typ := if is_void { 'void' } else { 'Array_${eltyp}' }
rec_sym := g.table.sym(node.receiver_type)
len := (rec_sym.info as ast.ArrayFixed).size
thread_arr_typ := rec_sym.cname
fn_name := '${thread_arr_typ}_wait'
mut should_register := false
lock g.waiter_fns {
if fn_name !in g.waiter_fns {
g.waiter_fns << fn_name
should_register = true
}
}
if should_register {
if is_void {
g.register_thread_void_wait_call()
g.waiter_fn_definitions.writeln('void ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
void ${fn_name}(${thread_arr_typ} a) {
for (int i = 0; i < ${len}; ++i) {
${thread_typ} t = ((${thread_typ}*)a)[i];
if (t == 0) continue;
__v_thread_wait(t);
}
}')
} else {
g.waiter_fn_definitions.writeln('${ret_typ} ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
${ret_typ} ${fn_name}(${thread_arr_typ} a) {
${ret_typ} res = __new_array_with_default(${len}, ${len}, sizeof(${eltyp}), 0);
for (int i = 0; i < ${len}; ++i) {
${thread_typ} t = ((${thread_typ}*)a)[i];')
if g.pref.os == .windows {
g.gowrappers.writeln('\t\tif (t.handle == 0) continue;')
} else {
g.gowrappers.writeln('\t\tif (t == 0) continue;')
}
g.gowrappers.writeln('\t\t((${eltyp}*)res.data)[i] = __v_thread_${eltyp}_wait(t);
}
return res;
}')
}
}
return fn_name
}

fn (mut g Gen) register_chan_pop_option_call(opt_el_type string, styp string) {
g.chan_pop_options[opt_el_type] = styp
}
Expand Down
117 changes: 117 additions & 0 deletions vlib/v/gen/c/spawn_and_go.v
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ fn (mut g Gen) create_waiter_handler(call_expr ast.CallExpr, s_ret_typ string, g
}
g.waiter_fn_definitions.writeln('${s_ret_typ} ${waiter_fn_name}(${gohandle_name} thread);')
g.gowrappers.writeln('\n${s_ret_typ} ${waiter_fn_name}(${gohandle_name} thread) {')
g.gowrappers.writeln('\tif ((unsigned long int)thread == 0) { _v_panic(_SLIT("unable to join thread")); }')
mut c_ret_ptr_ptr := 'NULL'
call_ret_type := call_expr.return_type
if call_ret_type != ast.void_type {
Expand Down Expand Up @@ -444,3 +445,119 @@ fn (mut g Gen) create_thread_type(call_expr ast.CallExpr, s_ret_typ string, name
}
g.gowrappers.writeln('}')
}

fn (mut g Gen) register_thread_void_wait_call() {
lock g.waiter_fns {
if '__v_thread_wait' in g.waiter_fns {
return
}
g.waiter_fns << '__v_thread_wait'
g.waiter_fn_definitions.writeln('void __v_thread_wait(__v_thread thread);')
}
g.gowrappers.writeln('void __v_thread_wait(__v_thread thread) {')
g.gowrappers.writeln('\tif ((unsigned long int)thread == 0) { _v_panic(_SLIT("unable to join thread")); }')
if g.pref.os == .windows {
g.gowrappers.writeln('\tu32 stat = WaitForSingleObject(thread, INFINITE);')
} else {
g.gowrappers.writeln('\tint stat = pthread_join(thread, (void **)NULL);')
}
g.gowrappers.writeln('\tif (stat != 0) { _v_panic(_SLIT("unable to join thread")); }')
if g.pref.os == .windows {
g.gowrappers.writeln('\tCloseHandle(thread);')
}
g.gowrappers.writeln('}')
}

fn (mut g Gen) register_thread_array_wait_call(eltyp string) string {
is_void := eltyp == 'void'
thread_typ := if is_void { '__v_thread' } else { '__v_thread_${eltyp}' }
ret_typ := if is_void { 'void' } else { 'Array_${eltyp}' }
thread_arr_typ := 'Array_${thread_typ}'
fn_name := '${thread_arr_typ}_wait'
mut should_register := false
lock g.waiter_fns {
if fn_name !in g.waiter_fns {
g.waiter_fns << fn_name
should_register = true
}
}
if should_register {
if is_void {
g.register_thread_void_wait_call()
g.waiter_fn_definitions.writeln('void ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
void ${fn_name}(${thread_arr_typ} a) {
for (int i = 0; i < a.len; ++i) {
${thread_typ} t = ((${thread_typ}*)a.data)[i];
if (t == 0) continue;
__v_thread_wait(t);
}
}')
} else {
g.waiter_fn_definitions.writeln('${ret_typ} ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
${ret_typ} ${fn_name}(${thread_arr_typ} a) {
${ret_typ} res = __new_array_with_default(a.len, a.len, sizeof(${eltyp}), 0);
for (int i = 0; i < a.len; ++i) {
${thread_typ} t = ((${thread_typ}*)a.data)[i];')
if g.pref.os == .windows {
g.gowrappers.writeln('\t\tif (t.handle == 0) continue;')
} else {
g.gowrappers.writeln('\t\tif (t == 0) continue;')
}
g.gowrappers.writeln('\t\t((${eltyp}*)res.data)[i] = __v_thread_${eltyp}_wait(t);
}
return res;
}')
}
}
return fn_name
}

fn (mut g Gen) register_thread_fixed_array_wait_call(node ast.CallExpr, eltyp string) string {
is_void := eltyp == 'void'
thread_typ := if is_void { '__v_thread' } else { '__v_thread_${eltyp}' }
ret_typ := if is_void { 'void' } else { 'Array_${eltyp}' }
rec_sym := g.table.sym(node.receiver_type)
len := (rec_sym.info as ast.ArrayFixed).size
thread_arr_typ := rec_sym.cname
fn_name := '${thread_arr_typ}_wait'
mut should_register := false
lock g.waiter_fns {
if fn_name !in g.waiter_fns {
g.waiter_fns << fn_name
should_register = true
}
}
if should_register {
if is_void {
g.register_thread_void_wait_call()
g.waiter_fn_definitions.writeln('void ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
void ${fn_name}(${thread_arr_typ} a) {
for (int i = 0; i < ${len}; ++i) {
${thread_typ} t = ((${thread_typ}*)a)[i];
if (t == 0) continue;
__v_thread_wait(t);
}
}')
} else {
g.waiter_fn_definitions.writeln('${ret_typ} ${fn_name}(${thread_arr_typ} a);')
g.gowrappers.writeln('
${ret_typ} ${fn_name}(${thread_arr_typ} a) {
${ret_typ} res = __new_array_with_default(${len}, ${len}, sizeof(${eltyp}), 0);
for (int i = 0; i < ${len}; ++i) {
${thread_typ} t = ((${thread_typ}*)a)[i];')
if g.pref.os == .windows {
g.gowrappers.writeln('\t\tif (t.handle == 0) continue;')
} else {
g.gowrappers.writeln('\t\tif (t == 0) continue;')
}
g.gowrappers.writeln('\t\t((${eltyp}*)res.data)[i] = __v_thread_${eltyp}_wait(t);
}
return res;
}')
}
}
return fn_name
}

0 comments on commit b4e121f

Please sign in to comment.