Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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" + '
std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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('^' + ".*" + ' std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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('^' + ".*" + ' std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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" + ' std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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('^' + ".*" + ' std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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('^' + ".*" + ' std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987
, '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); } })(); })(); std.mem.zeroes: Zero out entire `extern union`, including padding by jayschwa · Pull Request #17286 · ziglang/zig · GitHub
Skip to content

std.mem.zeroes: Zero out entire extern union, including padding - #17286

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern
Oct 1, 2023
Merged

std.mem.zeroes: Zero out entire extern union, including padding#17286
andrewrk merged 1 commit into
ziglang:masterfrom
jayschwa:mem-zeroes-extern

Conversation

@jayschwa

@jayschwajayschwa commented Sep 26, 2023

Copy link
Copy Markdown
Contributor

Fixes#17258

Comment threadlib/std/mem.zig Outdated
@jayschwa
jayschwaforce-pushed the mem-zeroes-extern branch 2 times, most recently from 065afea to d611c75CompareSeptember 27, 2023 20:58
@jayschwa

Copy link
Copy Markdown
ContributorAuthor

@kcbanner, I'm running into a problem with walkStackWindows after these changes. std.mem.zeroes is being called on a structure which contains non-nullable pointers, resulting in the error: "Only nullable and allowzero pointers can be set to zero."

varhistory_table: windows.UNWIND_HISTORY_TABLE=std.mem.zeroes(windows.UNWIND_HISTORY_TABLE);

zig/lib/std/os/windows.zig

Lines 4105 to 4108 in ab3ac1e

pubconstUNWIND_HISTORY_TABLE_ENTRY=externstruct {
ImageBase: ULONG64,
FunctionEntry: *Self.RUNTIME_FUNCTION,
};

I think there are two ways this could be fixed:

  1. Change the FunctionEntry field type to ?*Self.RUNTIME_FUNCTION. This is equivalent to what @cImport would do if the structure were being translated from the windows C header.
  2. history_table appears to only be an output parameter of RtlLookupFunctionEntry, so it could be initialized with undefined instead of std.mem.zeroes.

Which way do you think is better?

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

It looks like history_table isn't even read, so I will start testing with it initialized to undefined. Still open to suggestions though.

@kcbanner

Copy link
Copy Markdown
Contributor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

@jayschwa

Copy link
Copy Markdown
ContributorAuthor

I think option 1 (make the field an optional pointer) makes sense, that was an oversight on my part when I added it.

This is the change that ended up working. Initializing history_table to undefined caused problems. Maybe it's actually an in-out parameter, even though the Windows docs don't say that.

@andrewrkandrewrk 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.

For both extern structs and extern unions, it should be:

varitem: T=undefined;
@memset(asBytes(&item), 0);
returnitem;

If I understand correctly, the motivation for making these changes here is that the compiler is handling this perfectly correct code (for structs; extern unions should be changed to this too) in a problematic way.

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

@kcbanner

Copy link
Copy Markdown
Contributor

I suggest, instead of working around this in the standard library, to work around it in the implementation of @memset in the compiler.

I'm working on this problem here: https://github.com/ziglang/zig/compare/master...kcbanner:zig:extern_union_comptime_memory?expand=1

I'm tracking down one last case with writing to fields of packed unions overwriting too many bits, then I'll PR it.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

I chose to recursively initialize the fields for two reasons:

  1. It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.
  2. It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open. I'm not sure if Zig will ever support that scenario, but if it does, this bit of code won't need to change.

If you still think plain @memset is the way to go, I will change it.

@andrewrk

Copy link
Copy Markdown
Member

It provides additional guard rails to ensure zero values make sense for the fields being initialized. For example, it caught the non-nullable pointers in windows.UNWIND_HISTORY_TABLE.

In Zig, extern structs have well-defined memory layout, which means that they can be used as a bag of bytes that has anything there. It would be illegal behavior if zig code dereferenced one of the non-optional pointers from windows.UNWIND_HISTORY_TABLE which had been set to zero in this manner, however, it would have been perfectly legal to send such a struct instance over the C ABI boundary, or even to another Zig function which pointer-casted the struct to some other type and began operating on it.

Therefore I think the meaning of std.mem.zeroes for extern structs and unions should be defined in terms of setting the entire memory region to 0 bytes.

It ensures pointers are initialized to "null" instead of "0", which I acknowledge is pedantic. Situations where "null" is not "0" under the hood are probably vanishingly small, but C does leave that door open.

Zig does not define optional pointers in terms of the C programming language. Zig defines the null value of *T to be address 0. https://ziglang.org/documentation/0.11.0/#Optional-Pointers

There is no door open; the Zig language stands on its own and does not depend on the C language specification.

@jayschwa

jayschwa commented Oct 1, 2023

Copy link
Copy Markdown
ContributorAuthor

Okay, I'll change it to plain @memset.

@kcbanner, should I keep the Windows structure change?

Update: I decided to drop that other commit since the Windows structure change will no longer be necessary.

@jayschwa
jayschwa marked this pull request as draft October 1, 2023 04:33
@jayschwajayschwa changed the title std.mem.zeroes: Improve handling of extern struct and extern unionstd.mem.zeroes: Zero out entire extern union, including paddingOct 1, 2023
@jayschwa
jayschwa marked this pull request as ready for review October 1, 2023 05:06
@jayschwa
jayschwa requested a review from andrewrkOctober 1, 2023 05:07
@andrewrk
andrewrk enabled auto-merge (rebase) October 1, 2023 05:08
@andrewrk
andrewrk merged commit d8bfbbb into ziglang:masterOct 1, 2023
@jayschwa
jayschwa deleted the mem-zeroes-extern branch November 22, 2023 22:18
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

std.mem.zeroes does not zero entire extern union

4 participants

@jayschwa@kcbanner@andrewrk@vesim987