Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); [mono][debugger] Debugger method invokes dont' handle ref fields in ref structs by thaystg · Pull Request #76332 · dotnet/runtime · GitHub
Skip to content

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs - #76332

Merged
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field
Jan 4, 2023
Merged

[mono][debugger] Debugger method invokes dont' handle ref fields in ref structs#76332
thaystg merged 9 commits into
dotnet:mainfrom
thaystg:thays_fix_debug_by_ref_field

Conversation

@thaystg

Copy link
Copy Markdown
Member

@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @thaystg
See info in area-owners.md if you want to be subscribed.

Issue Details

#75774 (comment)

Author:thaystg
Assignees:-
Labels:

area-Debugger-mono

Milestone:-

@lambdageek

Copy link
Copy Markdown
Member

I'll take a look in more detail later today, but overall this looks good.

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not very confident about the size calculation. I'd like to see a comment somewhere that summarizes the rules.

Comment threadsrc/mono/mono/component/debugger-agent.c
/* We send these as vtypes, so we get them back as such */
g_assert (type == MONO_TYPE_VALUETYPE);
/* Fall through */
handle_vtype:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: indentation

Comment on lines +5607 to +5609
*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing. (Maybe a comment is enough).

This is what I think it's doing:

  1. We're going to decode a value
  2. The value will be placed into the extra space we allocated starting at *extra_space.
  3. At the beginning, addr is a pointer to some storage. We will write into that storage the address of the value we're decoding.
  4. Then we update addr to also point at the beginning of the extra space, because this is where the fields of the value will be stored.

Finally, we bump *extra_space so that if we need additional extra storage, it will use the extra space after the current value.

*(guint8**)addr = *extra_space;
guint8 *buf_int = buf;
addr = *(guint8**)addr;
*extra_space += decode_value_compute_size (t, type, domain, buf_int, &buf_int, limit, from_by_ref_value_type);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why isn't the last argument TRUE? isn't the whole current value going into extra space?

Comment on lines +5466 to +5469
if (!m_type_is_byref (f->type) && !m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)) && !from_by_ref_value_type)
decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, FALSE);
else
ret += decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, m_type_is_byref (f->type) || m_class_is_byreflike (mono_class_from_mono_type_internal (f->type)));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was really confused what from_by_ref_value_type is used for.

But I think this is the only place where it actually makes a difference, right?

And its purpose is to decide if the current field needs extra space.

So we're saying - a value will need to be stored into extra space if:

  1. It is byref,
  2. or it is a ref struct
  3. or the current field is part of a value type that was byref in some outer struct.

It might be clearer to do something like:

/* byval members of the current field will need to be in extra_space */gbooleanmembers_in_extra_space=m_type_is_byref (f->type) ||m_class_is_byreflike (...);
/* does the current field need to go in extra_space? Yes if it's recursively in a by_ref_value_type, or if it is itself byref or a ref struct */gbooleancur_field_in_extra_space=from_by_ref_value_type||members_in_extra_space;
intfield_size=decode_value_compute_size (f->type, 0, domain, buf, &buf, limit, members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

And actually I think I don't understand why it's like this.

Shouldn't it be somthing like:

gbooleancur_field_in_extra_space=from_by_ref_value_type;
gbooleanmembers_in_extra_space=cur_field_in_extra_space||m_type_is_byref (f->type);
gsizefield_size=decode_value_compute_size (f->type, ..., members_in_extra_space);
if (cur_field_in_extra_space)
ret+=field_size;

ie once you're in extra_space, you're stuck in extra space for all the other structs you recurse into. And additionallly if any of them have byref fields, those values need to be in extra_space too.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if f->type is byref, don't you also need
if (cur_field_in_extra_space) ret += sizeof(gpointer); ?

If the current field is ref double you need to store the double in extra_space and you also need to store a pointer in the current structure, I think.

@thaystg

Copy link
Copy Markdown
MemberAuthor

@lambdageek when you have time can you review it again, I addressed all your comments I think :)

@lambdageeklambdageek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra condition looking at the byval_arg needed somewhere, or is it dead code from a previous revision? might be clearer to remove it for now

#define GET_EXTRA_SPACE_FOR_REF_FIELDS(klass) \
extra_space_size = 0; \
extra_space = NULL; \
if (m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) || m_class_is_byreflike (klass))) { \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_class_is_valuetype (klass) && (m_type_is_byref (m_class_get_byval_arg (klass)) can't be true in mono right now. the byval_arg of every MonoClass is not a ref type.

(In my ref ref C prototype from hack week a couple years ago, we added a MonoClass for byref types, so this might be ok for future-proofing, but right now it won't do anything).

Probably you need a MonoType here

@thaystg
thaystg merged commit 2975fa4 into dotnet:mainJan 4, 2023
Console.WriteLine(typeof(object).Assembly.FullName);
Console.WriteLine(System.Reflection.Assembly.GetEntryAssembly ());
Console.WriteLine(System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
Run();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thaystg oops. I missed this during code review - I thought this was in a debugger test, not in the HelloWorld sample. Can you revert it

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry also!
#80390

@ghostghost locked as resolved and limited conversation to collaborators Feb 9, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@thaystg@lambdageek