Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault, caused indirectly, by using mut x := []X{ len: positive }, where X is sumtype or interface #20272

Closed
MCausc78 opened this issue Dec 25, 2023 · 8 comments · Fixed by #20279
Labels
Bug This tag is applied to issues which reports bugs. Generics[T] Bugs/feature requests, that are related to the V generics. Nicer V Errors Bugs/feature requests, related to improving V error messages. Unit: Checker Bugs/feature requests, that are related to the type checker. Unit: Compiler Bugs/feature requests, that are related to the V compiler in general.

Comments

@MCausc78
Copy link
Contributor

MCausc78 commented Dec 25, 2023

Describe the bug

<title>

Reproduction Steps

import x.json2

pub enum ComponentType {
	action_row         = 1
	text_input         = 4
}

pub fn (ct ComponentType) build() json2.Any {
	return json2.Any(int(ct))
}

pub interface Component {
	is_component()
}

pub struct ActionRow {
pub:
	components []Component
}

fn (_ ActionRow) is_component() {}

pub fn ActionRow.parse(j map[string]json2.Any) !ActionRow {
	return ActionRow{
		components: (j['components']! as []json2.Any).map(Component.parse(it)!)
	}
}

pub struct TextInput {
pub:
	custom_id string @[required]
	value ?string
}

fn (_ TextInput) is_component() {}

pub fn TextInput.parse(j json2.Any) !TextInput {
	match j {
		map[string]json2.Any {
			return TextInput{
				custom_id: j['custom_id']! as string
				value: if s := j['value'] {
					?string(s as string)
				} else {
					none
				}
			}
		}
		else {
			return error('expected text input to be object, got ${j.type_name()}')
		}
	}
}

pub fn Component.parse(j json2.Any) !Component {
	match j {
		map[string]json2.Any {
			typ := unsafe { ComponentType(j['type']!.int()) }
			match typ {
				.action_row {
					return ActionRow.parse(j)!
				}
				.text_input {
					return TextInput.parse(j)!
				}
			}
		}
		else {
			return error('expected component to be object, got ${j.type_name()}')
		}
	}
}

pub fn maybe_map[T, X](a []T, f fn(T) !X) ![]X {
	mut r := []X{len: a.len}
	for v in a {
		r << f(v)!
	}
	return r
}

pub struct ModalSubmitData {
pub:
	// the custom_id of the modal
	custom_id string
	// the values submitted by the user
	components []Component
}

pub fn ModalSubmitData.parse(j json2.Any) !ModalSubmitData {
	match j {
		map[string]json2.Any {
			return ModalSubmitData{
				custom_id: j['custom_id']! as string
				components: maybe_map[json2.Any, Component](j['components']! as []json2.Any, fn (o json2.Any) !Component {
					return Component.parse(o)!
				})!
			}
		}
		else {
			return error('expected modal submit data to be object, got ${j.type_name()}')
		}
	}
}

fn main() {
	d := ModalSubmitData.parse(json2.raw_decode('{"custom_id":"my_cool_modal","components":[{"type":1,"components":[{"value":"cool, really?","type":4,"custom_id":"name"}]}]}') or {
		assert false, 'Should decode without error: ${err}'
		exit(1)
	}) or {
		assert false, 'Should parse without error: ${err}'
		exit(1)
	}
	assert d.components == [
		ActionRow{
			components: [
				TextInput{
					custom_id: 'name'
					value: 'cool, really?'
				}
			]
		}
	]
}

Expected Behavior

Successful execution, and successful asserts

Current Behavior

Unhandled Exception 0xC0000005
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:8531: at print_backtrace_skipping_top_frames_tcc: Backtrace
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:8498: by print_backtrace_skipping_top_frames
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:9308: by unhandled_exception_handler
7ff8b177c5fa : by ???
7ff8b04a7d66 : at ???: RUNTIME ERROR: invalid memory access
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:3469: by indent_Array_main__Component_str
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:3463: by Array_main__Component_str
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:19305: by main__main
C:/Users/mclr/AppData/Local/Temp/v_0/test.11054853969225494829.tmp.c:19442: by wmain
004a5bd8 : by ???
004a5d3b : by ???
7ff8afd353e0 : by ???

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.3 30d6f7b

Environment details (OS name and version, etc.)

V full version: V 0.4.3 23ed1e9.30d6f7b
OS: windows, Microsoft Windows 11 Pro v22000 64-bit
Processor: 12 cpus, 64bit, little endian, 

getwd: D:\Games\Proekti\V\interactions
vexe: D:\Games\Proekti\V\v\v.exe
vexe mtime: 2023-12-25 19:00:40

vroot: OK, value: D:\Games\Proekti\V\v
VMODULES: OK, value: C:\Users\mclr\.vmodules
VTMP: OK, value: C:\Users\mclr\AppData\Local\Temp\v_0

Git version: git version 2.37.0.windows.1
Git vroot status: weekly.2023.51-35-g30d6f7b2
.git/config present: true

CC version:
thirdparty/tcc status: thirdparty-windows-amd64 a39eb79b

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

@MCausc78 MCausc78 added the Bug This tag is applied to issues which reports bugs. label Dec 25, 2023
@shove70
Copy link
Contributor

shove70 commented Dec 26, 2023

pub fn maybe_map[T, X](a []T, f fn(T) !X) ![]X {
	mut r := []X{len: a.len}
	for v in a {
		r << f(v)!
	}
	return r
}
pub fn maybe_map[T, X](a []T, f fn(T) !X) ![]X {
	mut r := []X{len: a.len}     // =====>    mut r := []X{cap: a.len}          cap
	for v in a {
		r << f(v)!
	}
	return r
}

A NULL reference element at the beginning of the array causes a segment fault

@shove70
Copy link
Contributor

shove70 commented Dec 26, 2023

dump(d) at main()

[a.v:105] d: ModalSubmitData{
    custom_id: 'my_cool_modal'
    components: [Component(ActionRow{
        components: [Component(TextInput{
            custom_id: 'name'
            value: Option('cool, really?')
        })]
    })]
}

@shove70 shove70 removed the Bug This tag is applied to issues which reports bugs. label Dec 26, 2023
@spytheman
Copy link
Member

spytheman commented Dec 26, 2023

@shove70, I think, that it is still a valid bug, since the problem is, that:
x := []X{len: some_length}
... when X is a sumtype or an interface type, is not well defined.

I think that in those cases, it should require x := unsafe{ []X{len: some_length} } for now, since the default elements will be invalid interface/sumtype values.

I also think, that we should think about how to provide a way to specify the defaults for sumtype values and interfaces.

@medvednikov what do you think?

@spytheman spytheman changed the title Segmentation fault Segmentation fault, caused indirectly, by using mut x := []X{ len: positive }, where X is sumtype or interface Dec 26, 2023
@spytheman spytheman added Unit: Compiler Bugs/feature requests, that are related to the V compiler in general. Generics[T] Bugs/feature requests, that are related to the V generics. Unit: Checker Bugs/feature requests, that are related to the type checker. Nicer V Errors Bugs/feature requests, related to improving V error messages. Bug This tag is applied to issues which reports bugs. labels Dec 26, 2023
@shove70
Copy link
Contributor

shove70 commented Dec 26, 2023

Yeah, yeah, that's right! 👍

@shove70
Copy link
Contributor

shove70 commented Dec 27, 2023

vlib/v/checker/tests/array_init_sum_type_without_init_value_and_len_err.vv
vlib/v/checker/tests/array_of_interfaces_with_len_without_init.vv

There are already 2 related test cases, but it is not triggered
Let me tease that out

@StunxFS
Copy link
Contributor

StunxFS commented Dec 27, 2023

I also think, that we should think about how to provide a way to specify the defaults for sumtype values and interfaces.

@spytheman , how about an attribute that indicates the default value to use?

@[default_value: SumType(5)]
type SumType = int | string

@[default_value: Iface(IfaceEmpty{})
interface Iface {}

struct IfaceEmpty {}

@shove70
Copy link
Contributor

shove70 commented Dec 27, 2023

The first variant’s zero value as default, It seems pretty good too

@shove70
Copy link
Contributor

shove70 commented Dec 28, 2023

I think, interfaces should not be considered, because interfaces are an abstraction, and the current "disallow empty interface initialization" approach can be left intact,
sumtype is a concrete type, so it's worth considering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This tag is applied to issues which reports bugs. Generics[T] Bugs/feature requests, that are related to the V generics. Nicer V Errors Bugs/feature requests, related to improving V error messages. Unit: Checker Bugs/feature requests, that are related to the type checker. Unit: Compiler Bugs/feature requests, that are related to the V compiler in general.
Projects
None yet
4 participants