Skip to content

add const_leak and reject interning non-leaked const_allocate ptrs #143595

New issue

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

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

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

fee1-dead
Copy link
Member

@fee1-dead fee1-dead commented Jul 7, 2025

Implements as discussed on Zulip: #t-compiler/const-eval > const heap

r? @rust-lang/wg-const-eval

Fixes #129233

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jul 7, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jul 7, 2025

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

@fee1-dead fee1-dead force-pushed the push-sylpykzkmynr branch 2 times, most recently from 0995420 to 67537c4 Compare July 7, 2025 16:31
@fee1-dead fee1-dead force-pushed the push-sylpykzkmynr branch from 67537c4 to 911c6a6 Compare July 7, 2025 16:33
@juntyr
Copy link
Contributor

juntyr commented Jul 7, 2025

I'm really excited about this experiment and the movement on const alloc, so thanks for working on it <3

),
};

// If an allocation is created in an another const,
Copy link
Contributor

Choose a reason for hiding this comment

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

For now we could just error on this. I don't think this should really happen. Either you leaked, then you don't have an owned value anymore, or you didn't, then it got an error

@@ -7,5 +7,6 @@ use std::intrinsics;

const BAR: *mut i32 = unsafe { intrinsics::const_allocate(4, 4) as *mut i32 };
//~^ error: mutable pointer in final value of constant
//~| error: encountered `const_allocate` pointer in final value that was not leaked
Copy link
Contributor

Choose a reason for hiding this comment

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

We also need a test that only errors with this error message and looks otherwise benign

size,
align,
interpret::MemoryKind::Machine(MemoryKind::Heap),
interpret::MemoryKind::Machine(MemoryKind::HeapLeaked),
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need a separate memory kind? I think the interner will be happy with anything that didn't get deallocated

Copy link
Contributor

Choose a reason for hiding this comment

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

Similar to how it interns stack allocations from the trailing expression

@rust-log-analyzer
Copy link
Collaborator

The job x86_64-gnu-llvm-19 failed! Check out the build log: (web) (plain enhanced) (plain)

Click to see the possible cause of the failure (guessed by this bot)
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 48)
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 51)
 - LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 68)
##[endgroup]
Setting extra environment values for docker:  --env ENABLE_GCC_CODEGEN=1 --env GCC_EXEC_PREFIX=/usr/lib/gcc/
[CI_JOB_NAME=x86_64-gnu-llvm-19]
[CI_JOB_NAME=x86_64-gnu-llvm-19]
debug: `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` configured.
---
sccache: Listening on address 127.0.0.1:4226
##[group]Configure the build
configure: processing command line
configure: 
configure: build.configure-args := ['--build=x86_64-unknown-linux-gnu', '--llvm-root=/usr/lib/llvm-19', '--enable-llvm-link-shared', '--set', 'rust.randomize-layout=true', '--set', 'rust.thin-lto-import-instr-limit=10', '--set', 'build.print-step-timings', '--enable-verbose-tests', '--set', 'build.metrics', '--enable-verbose-configure', '--enable-sccache', '--disable-manage-submodules', '--enable-locked-deps', '--enable-cargo-native-static', '--set', 'rust.codegen-units-std=1', '--set', 'dist.compression-profile=balanced', '--dist-compression-formats=xz', '--disable-dist-src', '--release-channel=nightly', '--enable-debug-assertions', '--enable-overflow-checks', '--enable-llvm-assertions', '--set', 'rust.verify-llvm-ir', '--set', 'rust.codegen-backends=llvm,cranelift,gcc', '--set', 'llvm.static-libstdcpp', '--set', 'gcc.download-ci-gcc=true', '--enable-new-symbol-mangling']
configure: build.build          := x86_64-unknown-linux-gnu
configure: target.x86_64-unknown-linux-gnu.llvm-config := /usr/lib/llvm-19/bin/llvm-config
configure: llvm.link-shared     := True
configure: rust.randomize-layout := True
configure: rust.thin-lto-import-instr-limit := 10
---
  Number of decisions:   4439
  longest path:          1159 (code:    152)
  longest backtrack:       66 (code:    428)
Shared 87642 out of 154040 states by creating 14936 new states, saving 72706
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/expmed.cc: In function ‘rtx_def* extract_bit_field_1(rtx, poly_uint64, poly_uint64, int, rtx, machine_mode, machine_mode, bool, bool, rtx_def**)’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/expmed.cc:1864:45: warning: ‘*(unsigned int*)((char*)&imode + offsetof(scalar_int_mode, scalar_int_mode::m_mode))’ may be used uninitialized [-Wmaybe-uninitialized]
 1864 |       rtx sub = extract_bit_field_as_subreg (mode1, op0, imode,
      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
 1865 |                                              bitsize, bitnum);
      |                                              ~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/expmed.cc:1824:19: note: ‘*(unsigned int*)((char*)&imode + offsetof(scalar_int_mode, scalar_int_mode::m_mode))’ was declared here
 1824 |   scalar_int_mode imode;
      |                   ^~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/gimple-range-gori.cc: In member function ‘void range_def_chain::dump(FILE*, basic_block, const char*)’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/gimple-range-gori.cc:318:19: warning: format not a string literal and no format arguments [-Wformat-security]
  318 |           fprintf (f, prefix);
      |           ~~~~~~~~^~~~~~~~~~~
---
                 from /checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/region-model.h:33,
                 from /checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/access-diagram.cc:38:
In constructor ‘ana::byte_range::byte_range(ana::byte_offset_t, ana::byte_size_t)’,
    inlined from ‘virtual text_art::table ana::string_literal_spatial_item::make_table(const ana::bit_to_table_map&, text_art::style_manager&) const’ at /checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/access-diagram.cc:1811:18:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/store.h:312:5: warning: ‘size_in_bytes.generic_wide_int<fixed_wide_int_storage<128> >::fixed_wide_int_storage<128>.fixed_wide_int_storage<128>::val[1]’ may be used uninitialized [-Wmaybe-uninitialized]
  312 |     m_size_in_bytes (size_in_bytes)
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/access-diagram.cc: In member function ‘virtual text_art::table ana::string_literal_spatial_item::make_table(const ana::bit_to_table_map&, text_art::style_manager&) const’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/analyzer/access-diagram.cc:1807:28: note: ‘size_in_bytes.generic_wide_int<fixed_wide_int_storage<128> >::fixed_wide_int_storage<128>.fixed_wide_int_storage<128>::val[1]’ was declared here
 1807 |                byte_size_t size_in_bytes
      |                            ^~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/diagnostic.cc: In function ‘void fancy_abort(const char*, int, const char*)’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/diagnostic.cc:1729:15: warning: format not a string literal and no format arguments [-Wformat-security]
 1729 |       fnotice (stderr, diagnostic_kind_text[DK_ICE]);
---
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/gcc.cc:7938:9: warning: ignoring return value of ‘ssize_t write(int, const void*, size_t)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
 7938 |   write (fd, "\n\n", 2);
      |   ~~~~~~^~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/gcc.cc: In member function ‘void driver::final_actions() const’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/gcc.cc:9315:13: warning: ignoring return value of ‘int truncate(const char*, __off_t)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
 9315 |     truncate(totruncate_file, 0);
      |     ~~~~~~~~^~~~~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/lto/lto-common.cc: In function ‘void lto_resolution_read(splay_tree, FILE*, lto_file*)’:
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/lto/lto-common.cc:2095:10: warning: ignoring return value of ‘int fscanf(FILE*, const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
 2095 |   fscanf (resolution, " ");   /* Read white space.  */
      |   ~~~~~~~^~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/lto/lto-common.cc:2097:9: warning: ignoring return value of ‘size_t fread(void*, size_t, size_t, FILE*)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
 2097 |   fread (obj_name, sizeof (char), name_len, resolution);
      |   ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/lto/lto-common.cc:2117:10: warning: ignoring return value of ‘int fscanf(FILE*, const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
 2117 |   fscanf (resolution, "%u", &num_symbols);
      |   ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/checkout/obj/build/x86_64-unknown-linux-gnu/gcc/src/gcc/../libgcc/libgcov-util.c: In function ‘gcov_info* gcov_read_profile_dir(const char*, int)’:
---
Applying io_quotes_use            to linux/blkzoned.h
Applying io_quotes_use            to linux/aspeed-p2a-ctrl.h
Applying io_quotes_use            to linux/vduse.h
Applying io_quotes_use            to linux/blkpg.h
Applying io_quotes_use            to linux/tps6594_pfsm.h
Applying io_quotes_use            to linux/uinput.h
Applying io_quotes_use            to linux/sockios.h
Applying io_quotes_use            to linux/usb/tmc.h
Applying io_quotes_use            to linux/nbd.h
Applying io_quotes_def            to linux/version.h
---
Applying io_quotes_def            to sudo_plugin.h
Applying io_quotes_use            to sudo_plugin.h
Applying io_quotes_use            to video/sisfb.h
Applying io_quotes_use            to scsi/cxlflash_ioctl.h
Applying io_quotes_use            to misc/mrvl_cn10k_dpi.h
Applying io_quotes_use            to misc/ocxl.h
Applying io_quotes_use            to misc/xilinx_sdfec.h
Applying io_quotes_use            to misc/cxl.h
Applying sun_malloc               to malloc.h
Applying machine_name             to openssl/e_os2.h
Applying io_quotes_use            to drm/exynos_drm.h
Applying io_quotes_use            to drm/qaic_accel.h
Applying io_quotes_use            to drm/amdgpu_drm.h
Applying io_quotes_use            to drm/xe_drm.h
Applying io_quotes_use            to drm/lima_drm.h
Applying io_quotes_use            to drm/omap_drm.h
Applying io_quotes_use            to drm/msm_drm.h
Applying io_quotes_use            to drm/vgem_drm.h
Applying io_quotes_use            to drm/vc4_drm.h
Applying io_quotes_use            to drm/drm.h
Applying io_quotes_use            to drm/tegra_drm.h
Applying io_quotes_use            to drm/habanalabs_accel.h
Applying io_quotes_use            to drm/v3d_drm.h
Applying io_quotes_use            to drm/etnaviv_drm.h
Applying io_quotes_use            to drm/i915_drm.h
Applying io_quotes_use            to drm/radeon_drm.h
Applying io_quotes_use            to drm/nouveau_drm.h
Applying io_quotes_use            to drm/panfrost_drm.h
Applying io_quotes_use            to drm/pvr_drm.h
Applying io_quotes_use            to sys/epoll.h
Applying machine_name             to sys/rseq.h
Applying io_quotes_use            to sys/raw.h
Applying io_quotes_use            to sys/mount.h
Applying machine_name             to sys/mount.h
---
---- [ui] tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs stdout ----
Saved the actual 32bit.stderr to `/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit/alloc_intrinsic_uninit.32bit.stderr`
diff of 32bit.stderr:

1 error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
2   --> $DIR/alloc_intrinsic_uninit.rs:7:1
3    |
- LL | const BAR: &i32 = unsafe { &*(intrinsics::const_allocate(4, 4) as *mut i32) };
+ LL | const BAR: &i32 = unsafe {
5    | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
6    |
7    = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.

Note: some mismatched output was normalized before being compared
- LL | const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory
+ LL | const BAR: &i32 = unsafe {


The actual 32bit.stderr differed from the expected 32bit.stderr
To update references, rerun the tests and pass the `--bless` flag
To only update this specific test, also pass `--test-args consts/const-eval/heap/alloc_intrinsic_uninit.rs`

error: 1 errors occurred comparing output.
status: exit status: 1
command: env -u RUSTC_LOG_COLOR RUSTC_ICE="0" RUST_BACKTRACE="short" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2/bin/rustc" "/checkout/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs" "-Zthreads=1" "-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX" "-Ztranslate-remapped-path-to-local-path=no" "-Z" "ignore-directory-in-diagnostics-source-blocks=/cargo" "-Z" "ignore-directory-in-diagnostics-source-blocks=/checkout/vendor" "--sysroot" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage2" "--target=i686-unknown-linux-gnu" "--check-cfg" "cfg(test,FALSE)" "--error-format" "json" "--json" "future-incompat" "-Ccodegen-units=1" "-Zui-testing" "-Zdeduplicate-diagnostics=no" "-Zwrite-long-types-to-disk=no" "-Cstrip=debuginfo" "--emit" "metadata" "-C" "prefer-dynamic" "--out-dir" "/checkout/obj/build/x86_64-unknown-linux-gnu/test/ui/consts/const-eval/heap/alloc_intrinsic_uninit" "-A" "unused" "-A" "internal_features" "-Crpath" "-Cdebuginfo=0" "-Lnative=/checkout/obj/build/i686-unknown-linux-gnu/native/rust-test-helpers" "-Clinker=x86_64-linux-gnu-gcc"
stdout: none
--- stderr -------------------------------
error[E0080]: constructing invalid value at .<deref>: encountered uninitialized memory, but expected an integer
##[error]  --> /checkout/tests/ui/consts/const-eval/heap/alloc_intrinsic_uninit.rs:7:1
   |
LL | const BAR: &i32 = unsafe { //~ ERROR: uninitialized memory
   | ^^^^^^^^^^^^^^^ it is undefined behavior to use this value
   |
   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
   = note: the raw bytes of the constant (size: 4, align: 4) {
               ╾─a3<imm>─╼                                     │ ╾──╼
           }

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0080`.

return Err(());
};

if matches!(kind, MemoryKind::Machine(x) if x.is_const_heap()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please turn this into an exhaustive match on the base memory kind enum.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this not reusing the may_leak method?

Copy link
Member

Choose a reason for hiding this comment

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

This isn't about leaking though, it's about interning. I don't think it is the same condition as what Miri's leak check needs?

kind: MemoryKind<M::MemoryKind>,
new_kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::Provenance>> {
self.reallocate_ptr_inner(
Copy link
Member

Choose a reason for hiding this comment

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

Why does this reallocate? I don't think that is the right semantics. It will be very hard to use this to intern a graph of allocations since you need to mutate the all pointers into the allocation. And it will be impossible to do this in a cyclic graph.

@RalfJung
Copy link
Member

RalfJung commented Jul 7, 2025

In terms of naming, I think we said that Box::leak would not be performing this operation, so "leak" seems like a suboptimal choice. Maybe something like "make_global" or "into_static" or so?

The original plan I proposed also makes the allocation immutable when it gets marked as global -- basically, this operation should indicate that you are done preparing this allocation and it is ready to be interned. (We actually intern it later as that's easier, but for the API this does not matter.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

const_heap feature can be used to leak mutable memory into final value of constant
7 participants