@shd101wyy/yo 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +17 -0
- package/README.md +80 -0
- package/out/cjs/index.cjs +51 -0
- package/out/cjs/yo-cli.cjs +2158 -0
- package/out/esm/index.mjs +51 -0
- package/out/types/src/codegen/async/runtime.d.ts +2 -0
- package/out/types/src/codegen/async/state-code-gen.d.ts +10 -0
- package/out/types/src/codegen/async/state-machine.d.ts +13 -0
- package/out/types/src/codegen/c/collection.d.ts +3 -0
- package/out/types/src/codegen/codegen-c.d.ts +12 -0
- package/out/types/src/codegen/constants.d.ts +3 -0
- package/out/types/src/codegen/expressions/array.d.ts +4 -0
- package/out/types/src/codegen/expressions/generation.d.ts +11 -0
- package/out/types/src/codegen/expressions/index.d.ts +2 -0
- package/out/types/src/codegen/functions/collection.d.ts +5 -0
- package/out/types/src/codegen/functions/context.d.ts +57 -0
- package/out/types/src/codegen/functions/generation.d.ts +25 -0
- package/out/types/src/codegen/functions/index.d.ts +2 -0
- package/out/types/src/codegen/index.d.ts +20 -0
- package/out/types/src/codegen/parallelism/runtime.d.ts +2 -0
- package/out/types/src/codegen/types/collection.d.ts +8 -0
- package/out/types/src/codegen/types/generation.d.ts +13 -0
- package/out/types/src/codegen/types/index.d.ts +2 -0
- package/out/types/src/codegen/utils/fixup.d.ts +2 -0
- package/out/types/src/codegen/utils/index.d.ts +77 -0
- package/out/types/src/codegen/values/index.d.ts +1 -0
- package/out/types/src/emitter.d.ts +11 -0
- package/out/types/src/env.d.ts +85 -0
- package/out/types/src/error.d.ts +45 -0
- package/out/types/src/evaluator/async/await-analysis-types.d.ts +23 -0
- package/out/types/src/evaluator/async/await-analysis.d.ts +5 -0
- package/out/types/src/evaluator/builtins/alignof.d.ts +8 -0
- package/out/types/src/evaluator/builtins/and_or.d.ts +8 -0
- package/out/types/src/evaluator/builtins/arc_fns.d.ts +58 -0
- package/out/types/src/evaluator/builtins/array_fns.d.ts +0 -0
- package/out/types/src/evaluator/builtins/as.d.ts +8 -0
- package/out/types/src/evaluator/builtins/async_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_assert.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_boolean_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_expect_error.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_list_fns.d.ts +33 -0
- package/out/types/src/evaluator/builtins/compt_print.d.ts +8 -0
- package/out/types/src/evaluator/builtins/compt_string_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/consume.d.ts +8 -0
- package/out/types/src/evaluator/builtins/drop.d.ts +8 -0
- package/out/types/src/evaluator/builtins/dup.d.ts +8 -0
- package/out/types/src/evaluator/builtins/expr_fns.d.ts +33 -0
- package/out/types/src/evaluator/builtins/future_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/gc.d.ts +8 -0
- package/out/types/src/evaluator/builtins/gensym.d.ts +8 -0
- package/out/types/src/evaluator/builtins/impl_constraint.d.ts +8 -0
- package/out/types/src/evaluator/builtins/macro_expand.d.ts +8 -0
- package/out/types/src/evaluator/builtins/numeric_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/panic.d.ts +8 -0
- package/out/types/src/evaluator/builtins/ptr_fns.d.ts +8 -0
- package/out/types/src/evaluator/builtins/quote.d.ts +13 -0
- package/out/types/src/evaluator/builtins/rc.d.ts +8 -0
- package/out/types/src/evaluator/builtins/sizeof.d.ts +8 -0
- package/out/types/src/evaluator/builtins/the.d.ts +8 -0
- package/out/types/src/evaluator/builtins/type_fns.d.ts +28 -0
- package/out/types/src/evaluator/builtins/va_start.d.ts +8 -0
- package/out/types/src/evaluator/builtins/var_fns.d.ts +18 -0
- package/out/types/src/evaluator/calls/array.d.ts +13 -0
- package/out/types/src/evaluator/calls/array_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/closure_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/compt_function.d.ts +19 -0
- package/out/types/src/evaluator/calls/compt_list_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/function.d.ts +16 -0
- package/out/types/src/evaluator/calls/function_type.d.ts +15 -0
- package/out/types/src/evaluator/calls/helper.d.ts +42 -0
- package/out/types/src/evaluator/calls/iso.d.ts +15 -0
- package/out/types/src/evaluator/calls/module_type.d.ts +11 -0
- package/out/types/src/evaluator/calls/numeric_type.d.ts +15 -0
- package/out/types/src/evaluator/calls/pointer.d.ts +8 -0
- package/out/types/src/evaluator/calls/pointer_type.d.ts +14 -0
- package/out/types/src/evaluator/calls/type.d.ts +12 -0
- package/out/types/src/evaluator/context.d.ts +169 -0
- package/out/types/src/evaluator/exprs/_expr.d.ts +8 -0
- package/out/types/src/evaluator/exprs/assignment.d.ts +9 -0
- package/out/types/src/evaluator/exprs/begin.d.ts +10 -0
- package/out/types/src/evaluator/exprs/binding.d.ts +12 -0
- package/out/types/src/evaluator/exprs/c_include.d.ts +8 -0
- package/out/types/src/evaluator/exprs/cond.d.ts +8 -0
- package/out/types/src/evaluator/exprs/destructuring_assignment.d.ts +33 -0
- package/out/types/src/evaluator/exprs/exists.d.ts +0 -0
- package/out/types/src/evaluator/exprs/expr.d.ts +9 -0
- package/out/types/src/evaluator/exprs/extern.d.ts +8 -0
- package/out/types/src/evaluator/exprs/identifer_and_operator.d.ts +9 -0
- package/out/types/src/evaluator/exprs/import.d.ts +9 -0
- package/out/types/src/evaluator/exprs/initialization_assignment.d.ts +8 -0
- package/out/types/src/evaluator/exprs/match.d.ts +8 -0
- package/out/types/src/evaluator/exprs/open.d.ts +8 -0
- package/out/types/src/evaluator/exprs/property_access.d.ts +8 -0
- package/out/types/src/evaluator/exprs/recur.d.ts +8 -0
- package/out/types/src/evaluator/exprs/subtype_of.d.ts +21 -0
- package/out/types/src/evaluator/exprs/test.d.ts +8 -0
- package/out/types/src/evaluator/exprs/typeof.d.ts +8 -0
- package/out/types/src/evaluator/exprs/while.d.ts +8 -0
- package/out/types/src/evaluator/index.d.ts +26 -0
- package/out/types/src/evaluator/types/array.d.ts +8 -0
- package/out/types/src/evaluator/types/closure.d.ts +8 -0
- package/out/types/src/evaluator/types/compt_list.d.ts +8 -0
- package/out/types/src/evaluator/types/concrete_module.d.ts +8 -0
- package/out/types/src/evaluator/types/dyn.d.ts +8 -0
- package/out/types/src/evaluator/types/enum.d.ts +8 -0
- package/out/types/src/evaluator/types/expr_synthesizer.d.ts +14 -0
- package/out/types/src/evaluator/types/field.d.ts +14 -0
- package/out/types/src/evaluator/types/fn_module.d.ts +8 -0
- package/out/types/src/evaluator/types/function.d.ts +58 -0
- package/out/types/src/evaluator/types/future_module.d.ts +8 -0
- package/out/types/src/evaluator/types/module.d.ts +19 -0
- package/out/types/src/evaluator/types/newtype.d.ts +8 -0
- package/out/types/src/evaluator/types/object.d.ts +8 -0
- package/out/types/src/evaluator/types/proofs.d.ts +0 -0
- package/out/types/src/evaluator/types/slice.d.ts +8 -0
- package/out/types/src/evaluator/types/struct.d.ts +8 -0
- package/out/types/src/evaluator/types/synthesizer.d.ts +16 -0
- package/out/types/src/evaluator/types/tuple.d.ts +18 -0
- package/out/types/src/evaluator/types/union.d.ts +8 -0
- package/out/types/src/evaluator/types/utils.d.ts +71 -0
- package/out/types/src/evaluator/types/validation.d.ts +3 -0
- package/out/types/src/evaluator/utils/array-utils.d.ts +15 -0
- package/out/types/src/evaluator/utils/closure.d.ts +35 -0
- package/out/types/src/evaluator/utils.d.ts +4 -0
- package/out/types/src/evaluator/values/anonymous_function.d.ts +8 -0
- package/out/types/src/evaluator/values/anonymous_module.d.ts +17 -0
- package/out/types/src/evaluator/values/anonymous_struct.d.ts +8 -0
- package/out/types/src/evaluator/values/array.d.ts +8 -0
- package/out/types/src/evaluator/values/boolean.d.ts +3 -0
- package/out/types/src/evaluator/values/char.d.ts +3 -0
- package/out/types/src/evaluator/values/compt_list.d.ts +8 -0
- package/out/types/src/evaluator/values/dyn.d.ts +8 -0
- package/out/types/src/evaluator/values/float.d.ts +4 -0
- package/out/types/src/evaluator/values/integer.d.ts +4 -0
- package/out/types/src/evaluator/values/module.d.ts +58 -0
- package/out/types/src/evaluator/values/string.d.ts +3 -0
- package/out/types/src/evaluator/values/tuple.d.ts +32 -0
- package/out/types/src/expr.d.ts +456 -0
- package/out/types/src/function-value.d.ts +42 -0
- package/out/types/src/index.d.ts +4 -0
- package/out/types/src/lexer.d.ts +2 -0
- package/out/types/src/logger.d.ts +1 -0
- package/out/types/src/module-manager.d.ts +30 -0
- package/out/types/src/naming-checker.d.ts +4 -0
- package/out/types/src/parser.d.ts +33 -0
- package/out/types/src/test-runner.d.ts +30 -0
- package/out/types/src/tests/codegen.test.d.ts +1 -0
- package/out/types/src/tests/fixme.test.d.ts +1 -0
- package/out/types/src/tests/module-manager.test.d.ts +1 -0
- package/out/types/src/tests/parser.test.d.ts +1 -0
- package/out/types/src/tests/sample.test.d.ts +0 -0
- package/out/types/src/tests/std.test.d.ts +1 -0
- package/out/types/src/token.d.ts +40 -0
- package/out/types/src/type-value.d.ts +7 -0
- package/out/types/src/types/compatibility.d.ts +16 -0
- package/out/types/src/types/creators.d.ts +73 -0
- package/out/types/src/types/definitions.d.ts +218 -0
- package/out/types/src/types/guards.d.ts +70 -0
- package/out/types/src/types/hierarchy.d.ts +4 -0
- package/out/types/src/types/index.d.ts +7 -0
- package/out/types/src/types/module_field.d.ts +2 -0
- package/out/types/src/types/tags.d.ts +45 -0
- package/out/types/src/types/utils.d.ts +50 -0
- package/out/types/src/unit-value.d.ts +7 -0
- package/out/types/src/utils.d.ts +6 -0
- package/out/types/src/value-tag.d.ts +29 -0
- package/out/types/src/value.d.ts +110 -0
- package/out/types/src/yo-cli.d.ts +1 -0
- package/out/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +57 -0
- package/scripts/check-liburing.js +76 -0
- package/std/alg/hash.yo +50 -0
- package/std/allocator.yo +113 -0
- package/std/allocators/c_allocator.yo +118 -0
- package/std/async.yo +13 -0
- package/std/collections/array_list.yo +415 -0
- package/std/collections/hash_map.yo +482 -0
- package/std/collections/hash_set.yo +706 -0
- package/std/collections/index.yo +11 -0
- package/std/collections/linked_list.yo +439 -0
- package/std/error.yo +0 -0
- package/std/gc.yo +10 -0
- package/std/index.yo +12 -0
- package/std/io/file.yo +191 -0
- package/std/io/index.yo +5 -0
- package/std/libc/assert.yo +39 -0
- package/std/libc/ctype.yo +57 -0
- package/std/libc/errno.yo +182 -0
- package/std/libc/float.yo +87 -0
- package/std/libc/index.yo +29 -0
- package/std/libc/limits.yo +65 -0
- package/std/libc/math.yo +679 -0
- package/std/libc/signal.yo +101 -0
- package/std/libc/stdatomic.yo +213 -0
- package/std/libc/stdint.yo +214 -0
- package/std/libc/stdio.yo +225 -0
- package/std/libc/stdlib.yo +204 -0
- package/std/libc/string.yo +151 -0
- package/std/libc/time.yo +92 -0
- package/std/libc/unistd.yo +130 -0
- package/std/monad.yo +152 -0
- package/std/prelude.yo +3094 -0
- package/std/string/index.yo +8 -0
- package/std/string/rune.yo +82 -0
- package/std/string/string.yo +288 -0
- package/std/sync.yo +95 -0
- package/std/thread.yo +36 -0
- package/std/time.yo +13 -0
- package/std/worker.yo +36 -0
- package/vendor/mimalloc/.gitattributes +12 -0
- package/vendor/mimalloc/CMakeLists.txt +763 -0
- package/vendor/mimalloc/LICENSE +21 -0
- package/vendor/mimalloc/SECURITY.md +41 -0
- package/vendor/mimalloc/azure-pipelines.yml +251 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64ec.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect-arm64ec.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect.lib +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect32.dll +0 -0
- package/vendor/mimalloc/bin/mimalloc-redirect32.lib +0 -0
- package/vendor/mimalloc/bin/minject-arm64.exe +0 -0
- package/vendor/mimalloc/bin/minject.exe +0 -0
- package/vendor/mimalloc/bin/minject32.exe +0 -0
- package/vendor/mimalloc/bin/readme.md +118 -0
- package/vendor/mimalloc/cmake/JoinPaths.cmake +23 -0
- package/vendor/mimalloc/cmake/mimalloc-config-version.cmake +19 -0
- package/vendor/mimalloc/cmake/mimalloc-config.cmake +14 -0
- package/vendor/mimalloc/contrib/docker/alpine/Dockerfile +23 -0
- package/vendor/mimalloc/contrib/docker/alpine-arm32v7/Dockerfile +28 -0
- package/vendor/mimalloc/contrib/docker/alpine-x86/Dockerfile +28 -0
- package/vendor/mimalloc/contrib/docker/manylinux-x64/Dockerfile +23 -0
- package/vendor/mimalloc/contrib/docker/readme.md +10 -0
- package/vendor/mimalloc/contrib/vcpkg/portfile.cmake +64 -0
- package/vendor/mimalloc/contrib/vcpkg/readme.md +40 -0
- package/vendor/mimalloc/contrib/vcpkg/usage +20 -0
- package/vendor/mimalloc/contrib/vcpkg/vcpkg-cmake-wrapper.cmake +20 -0
- package/vendor/mimalloc/contrib/vcpkg/vcpkg.json +48 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-a.svg +887 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-b.svg +1185 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-a.svg +757 -0
- package/vendor/mimalloc/doc/bench-2020/bench-c5-18xlarge-2020-01-20-rss-b.svg +1028 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-1.svg +769 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-a.svg +868 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-12xlarge-2020-01-16-b.svg +1157 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-2.svg +983 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-rss-1.svg +683 -0
- package/vendor/mimalloc/doc/bench-2020/bench-r5a-rss-2.svg +854 -0
- package/vendor/mimalloc/doc/bench-2020/bench-spec-rss.svg +713 -0
- package/vendor/mimalloc/doc/bench-2020/bench-spec.svg +713 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-1.svg +890 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-2.svg +1146 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-rss-1.svg +796 -0
- package/vendor/mimalloc/doc/bench-2020/bench-z4-rss-2.svg +974 -0
- package/vendor/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-a.svg +952 -0
- package/vendor/mimalloc/doc/bench-2021/bench-amd5950x-2021-01-30-b.svg +1255 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-a.svg +955 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-b.svg +1269 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-a.svg +836 -0
- package/vendor/mimalloc/doc/bench-2021/bench-c5-18xlarge-2021-01-30-rss-b.svg +1131 -0
- package/vendor/mimalloc/doc/bench-2021/bench-macmini-2021-01-30.svg +766 -0
- package/vendor/mimalloc/doc/doxyfile +2895 -0
- package/vendor/mimalloc/doc/ds-logo.jpg +0 -0
- package/vendor/mimalloc/doc/ds-logo.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-doc.h +1452 -0
- package/vendor/mimalloc/doc/mimalloc-doxygen.css +60 -0
- package/vendor/mimalloc/doc/mimalloc-logo-100.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-logo.png +0 -0
- package/vendor/mimalloc/doc/mimalloc-logo.svg +161 -0
- package/vendor/mimalloc/doc/spades-logo.png +0 -0
- package/vendor/mimalloc/doc/unreal-logo.svg +43 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj +500 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-lib.vcxproj.filters +108 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj +508 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-dll.vcxproj.filters +111 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-test-dep.vcxproj +355 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-override-test.vcxproj +360 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-api.vcxproj +295 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test-stress.vcxproj +292 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc-test.vcxproj +289 -0
- package/vendor/mimalloc/ide/vs2022/mimalloc.sln +151 -0
- package/vendor/mimalloc/include/mimalloc/atomic.h +557 -0
- package/vendor/mimalloc/include/mimalloc/internal.h +1153 -0
- package/vendor/mimalloc/include/mimalloc/prim.h +421 -0
- package/vendor/mimalloc/include/mimalloc/track.h +145 -0
- package/vendor/mimalloc/include/mimalloc/types.h +685 -0
- package/vendor/mimalloc/include/mimalloc-new-delete.h +66 -0
- package/vendor/mimalloc/include/mimalloc-override.h +68 -0
- package/vendor/mimalloc/include/mimalloc-stats.h +103 -0
- package/vendor/mimalloc/include/mimalloc.h +612 -0
- package/vendor/mimalloc/mimalloc.pc.in +11 -0
- package/vendor/mimalloc/readme.md +946 -0
- package/vendor/mimalloc/src/alloc-aligned.c +360 -0
- package/vendor/mimalloc/src/alloc-override.c +316 -0
- package/vendor/mimalloc/src/alloc-posix.c +185 -0
- package/vendor/mimalloc/src/alloc.c +692 -0
- package/vendor/mimalloc/src/arena-abandon.c +346 -0
- package/vendor/mimalloc/src/arena.c +1043 -0
- package/vendor/mimalloc/src/bitmap.c +441 -0
- package/vendor/mimalloc/src/bitmap.h +119 -0
- package/vendor/mimalloc/src/free.c +572 -0
- package/vendor/mimalloc/src/heap.c +733 -0
- package/vendor/mimalloc/src/init.c +714 -0
- package/vendor/mimalloc/src/libc.c +334 -0
- package/vendor/mimalloc/src/options.c +663 -0
- package/vendor/mimalloc/src/os.c +770 -0
- package/vendor/mimalloc/src/page-queue.c +390 -0
- package/vendor/mimalloc/src/page.c +1049 -0
- package/vendor/mimalloc/src/prim/emscripten/prim.c +249 -0
- package/vendor/mimalloc/src/prim/osx/alloc-override-zone.c +461 -0
- package/vendor/mimalloc/src/prim/osx/prim.c +9 -0
- package/vendor/mimalloc/src/prim/prim.c +76 -0
- package/vendor/mimalloc/src/prim/readme.md +9 -0
- package/vendor/mimalloc/src/prim/unix/prim.c +934 -0
- package/vendor/mimalloc/src/prim/wasi/prim.c +284 -0
- package/vendor/mimalloc/src/prim/windows/etw-mimalloc.wprp +61 -0
- package/vendor/mimalloc/src/prim/windows/etw.h +905 -0
- package/vendor/mimalloc/src/prim/windows/etw.man +0 -0
- package/vendor/mimalloc/src/prim/windows/prim.c +878 -0
- package/vendor/mimalloc/src/prim/windows/readme.md +17 -0
- package/vendor/mimalloc/src/random.c +258 -0
- package/vendor/mimalloc/src/segment-map.c +142 -0
- package/vendor/mimalloc/src/segment.c +1702 -0
- package/vendor/mimalloc/src/static.c +41 -0
- package/vendor/mimalloc/src/stats.c +635 -0
- package/vendor/mimalloc/test/CMakeLists.txt +56 -0
- package/vendor/mimalloc/test/main-override-dep.cpp +51 -0
- package/vendor/mimalloc/test/main-override-dep.h +11 -0
- package/vendor/mimalloc/test/main-override-static.c +539 -0
- package/vendor/mimalloc/test/main-override.c +36 -0
- package/vendor/mimalloc/test/main-override.cpp +497 -0
- package/vendor/mimalloc/test/main.c +46 -0
- package/vendor/mimalloc/test/readme.md +16 -0
- package/vendor/mimalloc/test/test-api-fill.c +343 -0
- package/vendor/mimalloc/test/test-api.c +466 -0
- package/vendor/mimalloc/test/test-stress.c +428 -0
- package/vendor/mimalloc/test/test-wrong.c +92 -0
- package/vendor/mimalloc/test/testhelper.h +49 -0
|
@@ -0,0 +1,572 @@
|
|
|
1
|
+
/* ----------------------------------------------------------------------------
|
|
2
|
+
Copyright (c) 2018-2024, Microsoft Research, Daan Leijen
|
|
3
|
+
This is free software; you can redistribute it and/or modify it under the
|
|
4
|
+
terms of the MIT license. A copy of the license can be found in the file
|
|
5
|
+
"LICENSE" at the root of this distribution.
|
|
6
|
+
-----------------------------------------------------------------------------*/
|
|
7
|
+
#if !defined(MI_IN_ALLOC_C)
|
|
8
|
+
#error "this file should be included from 'alloc.c' (so aliases can work from alloc-override)"
|
|
9
|
+
// add includes help an IDE
|
|
10
|
+
#include "mimalloc.h"
|
|
11
|
+
#include "mimalloc/internal.h"
|
|
12
|
+
#include "mimalloc/prim.h" // _mi_prim_thread_id()
|
|
13
|
+
#endif
|
|
14
|
+
|
|
15
|
+
// forward declarations
|
|
16
|
+
static void mi_check_padding(const mi_page_t* page, const mi_block_t* block);
|
|
17
|
+
static bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block);
|
|
18
|
+
static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block);
|
|
19
|
+
static void mi_stat_free(const mi_page_t* page, const mi_block_t* block);
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
// ------------------------------------------------------
|
|
23
|
+
// Free
|
|
24
|
+
// ------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
// forward declaration of multi-threaded free (`_mt`) (or free in huge block if compiled with MI_HUGE_PAGE_ABANDON)
|
|
27
|
+
static mi_decl_noinline void mi_free_block_mt(mi_page_t* page, mi_segment_t* segment, mi_block_t* block);
|
|
28
|
+
|
|
29
|
+
// regular free of a (thread local) block pointer
|
|
30
|
+
// fast path written carefully to prevent spilling on the stack
|
|
31
|
+
static inline void mi_free_block_local(mi_page_t* page, mi_block_t* block, bool track_stats, bool check_full)
|
|
32
|
+
{
|
|
33
|
+
// checks
|
|
34
|
+
if mi_unlikely(mi_check_is_double_free(page, block)) return;
|
|
35
|
+
mi_check_padding(page, block);
|
|
36
|
+
if (track_stats) { mi_stat_free(page, block); }
|
|
37
|
+
#if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN && !MI_GUARDED
|
|
38
|
+
if (!mi_page_is_huge(page)) { // huge page content may be already decommitted
|
|
39
|
+
memset(block, MI_DEBUG_FREED, mi_page_block_size(page));
|
|
40
|
+
}
|
|
41
|
+
#endif
|
|
42
|
+
if (track_stats) { mi_track_free_size(block, mi_page_usable_size_of(page, block)); } // faster then mi_usable_size as we already know the page and that p is unaligned
|
|
43
|
+
|
|
44
|
+
// actual free: push on the local free list
|
|
45
|
+
mi_block_set_next(page, block, page->local_free);
|
|
46
|
+
page->local_free = block;
|
|
47
|
+
if mi_unlikely(--page->used == 0) {
|
|
48
|
+
_mi_page_retire(page);
|
|
49
|
+
}
|
|
50
|
+
else if mi_unlikely(check_full && mi_page_is_in_full(page)) {
|
|
51
|
+
_mi_page_unfull(page);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Adjust a block that was allocated aligned, to the actual start of the block in the page.
|
|
56
|
+
// note: this can be called from `mi_free_generic_mt` where a non-owning thread accesses the
|
|
57
|
+
// `page_start` and `block_size` fields; however these are constant and the page won't be
|
|
58
|
+
// deallocated (as the block we are freeing keeps it alive) and thus safe to read concurrently.
|
|
59
|
+
mi_block_t* _mi_page_ptr_unalign(const mi_page_t* page, const void* p) {
|
|
60
|
+
mi_assert_internal(page!=NULL && p!=NULL);
|
|
61
|
+
|
|
62
|
+
size_t diff = (uint8_t*)p - page->page_start;
|
|
63
|
+
size_t adjust;
|
|
64
|
+
if mi_likely(page->block_size_shift != 0) {
|
|
65
|
+
adjust = diff & (((size_t)1 << page->block_size_shift) - 1);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
adjust = diff % mi_page_block_size(page);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (mi_block_t*)((uintptr_t)p - adjust);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// forward declaration for a MI_GUARDED build
|
|
75
|
+
#if MI_GUARDED
|
|
76
|
+
static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p); // forward declaration
|
|
77
|
+
static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) {
|
|
78
|
+
if (mi_block_ptr_is_guarded(block, p)) { mi_block_unguard(page, block, p); }
|
|
79
|
+
}
|
|
80
|
+
#else
|
|
81
|
+
static inline void mi_block_check_unguard(mi_page_t* page, mi_block_t* block, void* p) {
|
|
82
|
+
MI_UNUSED(page); MI_UNUSED(block); MI_UNUSED(p);
|
|
83
|
+
}
|
|
84
|
+
#endif
|
|
85
|
+
|
|
86
|
+
// free a local pointer (page parameter comes first for better codegen)
|
|
87
|
+
static void mi_decl_noinline mi_free_generic_local(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept {
|
|
88
|
+
MI_UNUSED(segment);
|
|
89
|
+
mi_block_t* const block = (mi_page_has_aligned(page) ? _mi_page_ptr_unalign(page, p) : (mi_block_t*)p);
|
|
90
|
+
mi_block_check_unguard(page, block, p);
|
|
91
|
+
mi_free_block_local(page, block, true /* track stats */, true /* check for a full page */);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// free a pointer owned by another thread (page parameter comes first for better codegen)
|
|
95
|
+
static void mi_decl_noinline mi_free_generic_mt(mi_page_t* page, mi_segment_t* segment, void* p) mi_attr_noexcept {
|
|
96
|
+
mi_block_t* const block = _mi_page_ptr_unalign(page, p); // don't check `has_aligned` flag to avoid a race (issue #865)
|
|
97
|
+
mi_block_check_unguard(page, block, p);
|
|
98
|
+
mi_free_block_mt(page, segment, block);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// generic free (for runtime integration)
|
|
102
|
+
void mi_decl_noinline _mi_free_generic(mi_segment_t* segment, mi_page_t* page, bool is_local, void* p) mi_attr_noexcept {
|
|
103
|
+
if (is_local) mi_free_generic_local(page,segment,p);
|
|
104
|
+
else mi_free_generic_mt(page,segment,p);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Get the segment data belonging to a pointer
|
|
108
|
+
// This is just a single `and` in release mode but does further checks in debug mode
|
|
109
|
+
// (and secure mode) to see if this was a valid pointer.
|
|
110
|
+
static inline mi_segment_t* mi_checked_ptr_segment(const void* p, const char* msg)
|
|
111
|
+
{
|
|
112
|
+
MI_UNUSED(msg);
|
|
113
|
+
|
|
114
|
+
#if (MI_DEBUG>0)
|
|
115
|
+
if mi_unlikely(((uintptr_t)p & (MI_INTPTR_SIZE - 1)) != 0 && !mi_option_is_enabled(mi_option_guarded_precise)) {
|
|
116
|
+
_mi_error_message(EINVAL, "%s: invalid (unaligned) pointer: %p\n", msg, p);
|
|
117
|
+
return NULL;
|
|
118
|
+
}
|
|
119
|
+
#endif
|
|
120
|
+
|
|
121
|
+
mi_segment_t* const segment = _mi_ptr_segment(p);
|
|
122
|
+
if mi_unlikely(segment==NULL) return segment;
|
|
123
|
+
|
|
124
|
+
#if (MI_DEBUG>0)
|
|
125
|
+
if mi_unlikely(!mi_is_in_heap_region(p)) {
|
|
126
|
+
#if (MI_INTPTR_SIZE == 8 && defined(__linux__))
|
|
127
|
+
if (((uintptr_t)p >> 40) != 0x7F) { // linux tends to align large blocks above 0x7F000000000 (issue #640)
|
|
128
|
+
#else
|
|
129
|
+
{
|
|
130
|
+
#endif
|
|
131
|
+
_mi_warning_message("%s: pointer might not point to a valid heap region: %p\n"
|
|
132
|
+
"(this may still be a valid very large allocation (over 64MiB))\n", msg, p);
|
|
133
|
+
if mi_likely(_mi_ptr_cookie(segment) == segment->cookie) {
|
|
134
|
+
_mi_warning_message("(yes, the previous pointer %p was valid after all)\n", p);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
#endif
|
|
139
|
+
#if (MI_DEBUG>0 || MI_SECURE>=4)
|
|
140
|
+
if mi_unlikely(_mi_ptr_cookie(segment) != segment->cookie) {
|
|
141
|
+
_mi_error_message(EINVAL, "%s: pointer does not point to a valid heap space: %p\n", msg, p);
|
|
142
|
+
return NULL;
|
|
143
|
+
}
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
return segment;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Free a block
|
|
150
|
+
// Fast path written carefully to prevent register spilling on the stack
|
|
151
|
+
void mi_free(void* p) mi_attr_noexcept
|
|
152
|
+
{
|
|
153
|
+
mi_segment_t* const segment = mi_checked_ptr_segment(p,"mi_free");
|
|
154
|
+
if mi_unlikely(segment==NULL) return;
|
|
155
|
+
|
|
156
|
+
const bool is_local = (_mi_prim_thread_id() == mi_atomic_load_relaxed(&segment->thread_id));
|
|
157
|
+
mi_page_t* const page = _mi_segment_page_of(segment, p);
|
|
158
|
+
|
|
159
|
+
if mi_likely(is_local) { // thread-local free?
|
|
160
|
+
if mi_likely(page->flags.full_aligned == 0) { // and it is not a full page (full pages need to move from the full bin), nor has aligned blocks (aligned blocks need to be unaligned)
|
|
161
|
+
// thread-local, aligned, and not a full page
|
|
162
|
+
mi_block_t* const block = (mi_block_t*)p;
|
|
163
|
+
mi_free_block_local(page, block, true /* track stats */, false /* no need to check if the page is full */);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// page is full or contains (inner) aligned blocks; use generic path
|
|
167
|
+
mi_free_generic_local(page, segment, p);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
// not thread-local; use generic path
|
|
172
|
+
mi_free_generic_mt(page, segment, p);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// return true if successful
|
|
177
|
+
bool _mi_free_delayed_block(mi_block_t* block) {
|
|
178
|
+
// get segment and page
|
|
179
|
+
mi_assert_internal(block!=NULL);
|
|
180
|
+
const mi_segment_t* const segment = _mi_ptr_segment(block);
|
|
181
|
+
mi_assert_internal(_mi_ptr_cookie(segment) == segment->cookie);
|
|
182
|
+
mi_assert_internal(_mi_thread_id() == segment->thread_id);
|
|
183
|
+
mi_page_t* const page = _mi_segment_page_of(segment, block);
|
|
184
|
+
|
|
185
|
+
// Clear the no-delayed flag so delayed freeing is used again for this page.
|
|
186
|
+
// This must be done before collecting the free lists on this page -- otherwise
|
|
187
|
+
// some blocks may end up in the page `thread_free` list with no blocks in the
|
|
188
|
+
// heap `thread_delayed_free` list which may cause the page to be never freed!
|
|
189
|
+
// (it would only be freed if we happen to scan it in `mi_page_queue_find_free_ex`)
|
|
190
|
+
if (!_mi_page_try_use_delayed_free(page, MI_USE_DELAYED_FREE, false /* dont overwrite never delayed */)) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// collect all other non-local frees (move from `thread_free` to `free`) to ensure up-to-date `used` count
|
|
195
|
+
_mi_page_free_collect(page, false);
|
|
196
|
+
|
|
197
|
+
// and free the block (possibly freeing the page as well since `used` is updated)
|
|
198
|
+
mi_free_block_local(page, block, false /* stats have already been adjusted */, true /* check for a full page */);
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ------------------------------------------------------
|
|
203
|
+
// Multi-threaded Free (`_mt`)
|
|
204
|
+
// ------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
// Push a block that is owned by another thread on its page-local thread free
|
|
207
|
+
// list or it's heap delayed free list. Such blocks are later collected by
|
|
208
|
+
// the owning thread in `_mi_free_delayed_block`.
|
|
209
|
+
static void mi_decl_noinline mi_free_block_delayed_mt( mi_page_t* page, mi_block_t* block )
|
|
210
|
+
{
|
|
211
|
+
// Try to put the block on either the page-local thread free list,
|
|
212
|
+
// or the heap delayed free list (if this is the first non-local free in that page)
|
|
213
|
+
mi_thread_free_t tfreex;
|
|
214
|
+
bool use_delayed;
|
|
215
|
+
mi_thread_free_t tfree = mi_atomic_load_relaxed(&page->xthread_free);
|
|
216
|
+
do {
|
|
217
|
+
use_delayed = (mi_tf_delayed(tfree) == MI_USE_DELAYED_FREE);
|
|
218
|
+
if mi_unlikely(use_delayed) {
|
|
219
|
+
// unlikely: this only happens on the first concurrent free in a page that is in the full list
|
|
220
|
+
tfreex = mi_tf_set_delayed(tfree,MI_DELAYED_FREEING);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// usual: directly add to page thread_free list
|
|
224
|
+
mi_block_set_next(page, block, mi_tf_block(tfree));
|
|
225
|
+
tfreex = mi_tf_set_block(tfree,block);
|
|
226
|
+
}
|
|
227
|
+
} while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex));
|
|
228
|
+
|
|
229
|
+
// If this was the first non-local free, we need to push it on the heap delayed free list instead
|
|
230
|
+
if mi_unlikely(use_delayed) {
|
|
231
|
+
// racy read on `heap`, but ok because MI_DELAYED_FREEING is set (see `mi_heap_delete` and `mi_heap_collect_abandon`)
|
|
232
|
+
mi_heap_t* const heap = (mi_heap_t*)(mi_atomic_load_acquire(&page->xheap)); //mi_page_heap(page);
|
|
233
|
+
mi_assert_internal(heap != NULL);
|
|
234
|
+
if (heap != NULL) {
|
|
235
|
+
// add to the delayed free list of this heap. (do this atomically as the lock only protects heap memory validity)
|
|
236
|
+
mi_block_t* dfree = mi_atomic_load_ptr_relaxed(mi_block_t, &heap->thread_delayed_free);
|
|
237
|
+
do {
|
|
238
|
+
mi_block_set_nextx(heap,block,dfree, heap->keys);
|
|
239
|
+
} while (!mi_atomic_cas_ptr_weak_release(mi_block_t,&heap->thread_delayed_free, &dfree, block));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// and reset the MI_DELAYED_FREEING flag
|
|
243
|
+
tfree = mi_atomic_load_relaxed(&page->xthread_free);
|
|
244
|
+
do {
|
|
245
|
+
tfreex = tfree;
|
|
246
|
+
mi_assert_internal(mi_tf_delayed(tfree) == MI_DELAYED_FREEING);
|
|
247
|
+
tfreex = mi_tf_set_delayed(tfree,MI_NO_DELAYED_FREE);
|
|
248
|
+
} while (!mi_atomic_cas_weak_release(&page->xthread_free, &tfree, tfreex));
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Multi-threaded free (`_mt`) (or free in huge block if compiled with MI_HUGE_PAGE_ABANDON)
|
|
253
|
+
static void mi_decl_noinline mi_free_block_mt(mi_page_t* page, mi_segment_t* segment, mi_block_t* block)
|
|
254
|
+
{
|
|
255
|
+
// first see if the segment was abandoned and if we can reclaim it into our thread
|
|
256
|
+
if (_mi_option_get_fast(mi_option_abandoned_reclaim_on_free) != 0 &&
|
|
257
|
+
#if MI_HUGE_PAGE_ABANDON
|
|
258
|
+
segment->page_kind != MI_PAGE_HUGE &&
|
|
259
|
+
#endif
|
|
260
|
+
mi_atomic_load_relaxed(&segment->thread_id) == 0 && // segment is abandoned?
|
|
261
|
+
mi_prim_get_default_heap() != (mi_heap_t*)&_mi_heap_empty) // and we did not already exit this thread (without this check, a fresh heap will be initalized (issue #944))
|
|
262
|
+
{
|
|
263
|
+
// the segment is abandoned, try to reclaim it into our heap
|
|
264
|
+
if (_mi_segment_attempt_reclaim(mi_heap_get_default(), segment)) {
|
|
265
|
+
mi_assert_internal(_mi_thread_id() == mi_atomic_load_relaxed(&segment->thread_id));
|
|
266
|
+
mi_assert_internal(mi_heap_get_default()->tld->segments.subproc == segment->subproc);
|
|
267
|
+
mi_free(block); // recursively free as now it will be a local free in our heap
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// The padding check may access the non-thread-owned page for the key values.
|
|
273
|
+
// that is safe as these are constant and the page won't be freed (as the block is not freed yet).
|
|
274
|
+
mi_check_padding(page, block);
|
|
275
|
+
|
|
276
|
+
// adjust stats (after padding check and potentially recursive `mi_free` above)
|
|
277
|
+
mi_stat_free(page, block); // stat_free may access the padding
|
|
278
|
+
mi_track_free_size(block, mi_page_usable_size_of(page,block));
|
|
279
|
+
|
|
280
|
+
// for small size, ensure we can fit the delayed thread pointers without triggering overflow detection
|
|
281
|
+
_mi_padding_shrink(page, block, sizeof(mi_block_t));
|
|
282
|
+
|
|
283
|
+
if (segment->kind == MI_SEGMENT_HUGE) {
|
|
284
|
+
#if MI_HUGE_PAGE_ABANDON
|
|
285
|
+
// huge page segments are always abandoned and can be freed immediately
|
|
286
|
+
_mi_segment_huge_page_free(segment, page, block);
|
|
287
|
+
return;
|
|
288
|
+
#else
|
|
289
|
+
// huge pages are special as they occupy the entire segment
|
|
290
|
+
// as these are large we reset the memory occupied by the page so it is available to other threads
|
|
291
|
+
// (as the owning thread needs to actually free the memory later).
|
|
292
|
+
_mi_segment_huge_page_reset(segment, page, block);
|
|
293
|
+
#endif
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
#if (MI_DEBUG>0) && !MI_TRACK_ENABLED && !MI_TSAN // note: when tracking, cannot use mi_usable_size with multi-threading
|
|
297
|
+
memset(block, MI_DEBUG_FREED, mi_usable_size(block));
|
|
298
|
+
#endif
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// and finally free the actual block by pushing it on the owning heap
|
|
302
|
+
// thread_delayed free list (or heap delayed free list)
|
|
303
|
+
mi_free_block_delayed_mt(page,block);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
// ------------------------------------------------------
|
|
308
|
+
// Usable size
|
|
309
|
+
// ------------------------------------------------------
|
|
310
|
+
|
|
311
|
+
// Bytes available in a block
|
|
312
|
+
static size_t mi_decl_noinline mi_page_usable_aligned_size_of(const mi_page_t* page, const void* p) mi_attr_noexcept {
|
|
313
|
+
const mi_block_t* block = _mi_page_ptr_unalign(page, p);
|
|
314
|
+
const size_t size = mi_page_usable_size_of(page, block);
|
|
315
|
+
const ptrdiff_t adjust = (uint8_t*)p - (uint8_t*)block;
|
|
316
|
+
mi_assert_internal(adjust >= 0 && (size_t)adjust <= size);
|
|
317
|
+
const size_t aligned_size = (size - adjust);
|
|
318
|
+
#if MI_GUARDED
|
|
319
|
+
if (mi_block_ptr_is_guarded(block, p)) {
|
|
320
|
+
return aligned_size - _mi_os_page_size();
|
|
321
|
+
}
|
|
322
|
+
#endif
|
|
323
|
+
return aligned_size;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
static inline size_t _mi_usable_size(const void* p, const char* msg) mi_attr_noexcept {
|
|
327
|
+
const mi_segment_t* const segment = mi_checked_ptr_segment(p, msg);
|
|
328
|
+
if mi_unlikely(segment==NULL) return 0;
|
|
329
|
+
const mi_page_t* const page = _mi_segment_page_of(segment, p);
|
|
330
|
+
if mi_likely(!mi_page_has_aligned(page)) {
|
|
331
|
+
const mi_block_t* block = (const mi_block_t*)p;
|
|
332
|
+
return mi_page_usable_size_of(page, block);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
// split out to separate routine for improved code generation
|
|
336
|
+
return mi_page_usable_aligned_size_of(page, p);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
mi_decl_nodiscard size_t mi_usable_size(const void* p) mi_attr_noexcept {
|
|
341
|
+
return _mi_usable_size(p, "mi_usable_size");
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
// ------------------------------------------------------
|
|
346
|
+
// Free variants
|
|
347
|
+
// ------------------------------------------------------
|
|
348
|
+
|
|
349
|
+
void mi_free_size(void* p, size_t size) mi_attr_noexcept {
|
|
350
|
+
MI_UNUSED_RELEASE(size);
|
|
351
|
+
#if MI_DEBUG
|
|
352
|
+
const size_t available = _mi_usable_size(p,"mi_free_size");
|
|
353
|
+
mi_assert(p == NULL || size <= available || available == 0 /* invalid pointer */ );
|
|
354
|
+
#endif
|
|
355
|
+
mi_free(p);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
void mi_free_size_aligned(void* p, size_t size, size_t alignment) mi_attr_noexcept {
|
|
359
|
+
MI_UNUSED_RELEASE(alignment);
|
|
360
|
+
mi_assert(((uintptr_t)p % alignment) == 0);
|
|
361
|
+
mi_free_size(p,size);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
void mi_free_aligned(void* p, size_t alignment) mi_attr_noexcept {
|
|
365
|
+
MI_UNUSED_RELEASE(alignment);
|
|
366
|
+
mi_assert(((uintptr_t)p % alignment) == 0);
|
|
367
|
+
mi_free(p);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
// ------------------------------------------------------
|
|
372
|
+
// Check for double free in secure and debug mode
|
|
373
|
+
// This is somewhat expensive so only enabled for secure mode 4
|
|
374
|
+
// ------------------------------------------------------
|
|
375
|
+
|
|
376
|
+
#if (MI_ENCODE_FREELIST && (MI_SECURE>=4 || MI_DEBUG!=0))
|
|
377
|
+
// linear check if the free list contains a specific element
|
|
378
|
+
static bool mi_list_contains(const mi_page_t* page, const mi_block_t* list, const mi_block_t* elem) {
|
|
379
|
+
while (list != NULL) {
|
|
380
|
+
if (elem==list) return true;
|
|
381
|
+
list = mi_block_next(page, list);
|
|
382
|
+
}
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
static mi_decl_noinline bool mi_check_is_double_freex(const mi_page_t* page, const mi_block_t* block) {
|
|
387
|
+
// The decoded value is in the same page (or NULL).
|
|
388
|
+
// Walk the free lists to verify positively if it is already freed
|
|
389
|
+
if (mi_list_contains(page, page->free, block) ||
|
|
390
|
+
mi_list_contains(page, page->local_free, block) ||
|
|
391
|
+
mi_list_contains(page, mi_page_thread_free(page), block))
|
|
392
|
+
{
|
|
393
|
+
_mi_error_message(EAGAIN, "double free detected of block %p with size %zu\n", block, mi_page_block_size(page));
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
return false;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
#define mi_track_page(page,access) { size_t psize; void* pstart = _mi_page_start(_mi_page_segment(page),page,&psize); mi_track_mem_##access( pstart, psize); }
|
|
400
|
+
|
|
401
|
+
static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) {
|
|
402
|
+
bool is_double_free = false;
|
|
403
|
+
mi_block_t* n = mi_block_nextx(page, block, page->keys); // pretend it is freed, and get the decoded first field
|
|
404
|
+
if (((uintptr_t)n & (MI_INTPTR_SIZE-1))==0 && // quick check: aligned pointer?
|
|
405
|
+
(n==NULL || mi_is_in_same_page(block, n))) // quick check: in same page or NULL?
|
|
406
|
+
{
|
|
407
|
+
// Suspicious: decoded value a in block is in the same page (or NULL) -- maybe a double free?
|
|
408
|
+
// (continue in separate function to improve code generation)
|
|
409
|
+
is_double_free = mi_check_is_double_freex(page, block);
|
|
410
|
+
}
|
|
411
|
+
return is_double_free;
|
|
412
|
+
}
|
|
413
|
+
#else
|
|
414
|
+
static inline bool mi_check_is_double_free(const mi_page_t* page, const mi_block_t* block) {
|
|
415
|
+
MI_UNUSED(page);
|
|
416
|
+
MI_UNUSED(block);
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
#endif
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
// ---------------------------------------------------------------------------
|
|
423
|
+
// Check for heap block overflow by setting up padding at the end of the block
|
|
424
|
+
// ---------------------------------------------------------------------------
|
|
425
|
+
|
|
426
|
+
#if MI_PADDING // && !MI_TRACK_ENABLED
|
|
427
|
+
static bool mi_page_decode_padding(const mi_page_t* page, const mi_block_t* block, size_t* delta, size_t* bsize) {
|
|
428
|
+
*bsize = mi_page_usable_block_size(page);
|
|
429
|
+
const mi_padding_t* const padding = (mi_padding_t*)((uint8_t*)block + *bsize);
|
|
430
|
+
mi_track_mem_defined(padding,sizeof(mi_padding_t));
|
|
431
|
+
*delta = padding->delta;
|
|
432
|
+
uint32_t canary = padding->canary;
|
|
433
|
+
uintptr_t keys[2];
|
|
434
|
+
keys[0] = page->keys[0];
|
|
435
|
+
keys[1] = page->keys[1];
|
|
436
|
+
bool ok = (mi_ptr_encode_canary(page,block,keys) == canary && *delta <= *bsize);
|
|
437
|
+
mi_track_mem_noaccess(padding,sizeof(mi_padding_t));
|
|
438
|
+
return ok;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Return the exact usable size of a block.
|
|
442
|
+
static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) {
|
|
443
|
+
size_t bsize;
|
|
444
|
+
size_t delta;
|
|
445
|
+
bool ok = mi_page_decode_padding(page, block, &delta, &bsize);
|
|
446
|
+
mi_assert_internal(ok); mi_assert_internal(delta <= bsize);
|
|
447
|
+
return (ok ? bsize - delta : 0);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// When a non-thread-local block is freed, it becomes part of the thread delayed free
|
|
451
|
+
// list that is freed later by the owning heap. If the exact usable size is too small to
|
|
452
|
+
// contain the pointer for the delayed list, then shrink the padding (by decreasing delta)
|
|
453
|
+
// so it will later not trigger an overflow error in `mi_free_block`.
|
|
454
|
+
void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) {
|
|
455
|
+
size_t bsize;
|
|
456
|
+
size_t delta;
|
|
457
|
+
bool ok = mi_page_decode_padding(page, block, &delta, &bsize);
|
|
458
|
+
mi_assert_internal(ok);
|
|
459
|
+
if (!ok || (bsize - delta) >= min_size) return; // usually already enough space
|
|
460
|
+
mi_assert_internal(bsize >= min_size);
|
|
461
|
+
if (bsize < min_size) return; // should never happen
|
|
462
|
+
size_t new_delta = (bsize - min_size);
|
|
463
|
+
mi_assert_internal(new_delta < bsize);
|
|
464
|
+
mi_padding_t* padding = (mi_padding_t*)((uint8_t*)block + bsize);
|
|
465
|
+
mi_track_mem_defined(padding,sizeof(mi_padding_t));
|
|
466
|
+
padding->delta = (uint32_t)new_delta;
|
|
467
|
+
mi_track_mem_noaccess(padding,sizeof(mi_padding_t));
|
|
468
|
+
}
|
|
469
|
+
#else
|
|
470
|
+
static size_t mi_page_usable_size_of(const mi_page_t* page, const mi_block_t* block) {
|
|
471
|
+
MI_UNUSED(block);
|
|
472
|
+
return mi_page_usable_block_size(page);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
void _mi_padding_shrink(const mi_page_t* page, const mi_block_t* block, const size_t min_size) {
|
|
476
|
+
MI_UNUSED(page);
|
|
477
|
+
MI_UNUSED(block);
|
|
478
|
+
MI_UNUSED(min_size);
|
|
479
|
+
}
|
|
480
|
+
#endif
|
|
481
|
+
|
|
482
|
+
#if MI_PADDING && MI_PADDING_CHECK
|
|
483
|
+
|
|
484
|
+
static bool mi_verify_padding(const mi_page_t* page, const mi_block_t* block, size_t* size, size_t* wrong) {
|
|
485
|
+
size_t bsize;
|
|
486
|
+
size_t delta;
|
|
487
|
+
bool ok = mi_page_decode_padding(page, block, &delta, &bsize);
|
|
488
|
+
*size = *wrong = bsize;
|
|
489
|
+
if (!ok) return false;
|
|
490
|
+
mi_assert_internal(bsize >= delta);
|
|
491
|
+
*size = bsize - delta;
|
|
492
|
+
if (!mi_page_is_huge(page)) {
|
|
493
|
+
uint8_t* fill = (uint8_t*)block + bsize - delta;
|
|
494
|
+
const size_t maxpad = (delta > MI_MAX_ALIGN_SIZE ? MI_MAX_ALIGN_SIZE : delta); // check at most the first N padding bytes
|
|
495
|
+
mi_track_mem_defined(fill, maxpad);
|
|
496
|
+
for (size_t i = 0; i < maxpad; i++) {
|
|
497
|
+
if (fill[i] != MI_DEBUG_PADDING) {
|
|
498
|
+
*wrong = bsize - delta + i;
|
|
499
|
+
ok = false;
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
mi_track_mem_noaccess(fill, maxpad);
|
|
504
|
+
}
|
|
505
|
+
return ok;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) {
|
|
509
|
+
size_t size;
|
|
510
|
+
size_t wrong;
|
|
511
|
+
if (!mi_verify_padding(page,block,&size,&wrong)) {
|
|
512
|
+
_mi_error_message(EFAULT, "buffer overflow in heap block %p of size %zu: write after %zu bytes\n", block, size, wrong );
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
#else
|
|
517
|
+
|
|
518
|
+
static void mi_check_padding(const mi_page_t* page, const mi_block_t* block) {
|
|
519
|
+
MI_UNUSED(page);
|
|
520
|
+
MI_UNUSED(block);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
#endif
|
|
524
|
+
|
|
525
|
+
// only maintain stats for smaller objects if requested
|
|
526
|
+
#if (MI_STAT>0)
|
|
527
|
+
static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) {
|
|
528
|
+
MI_UNUSED(block);
|
|
529
|
+
mi_heap_t* const heap = mi_heap_get_default();
|
|
530
|
+
const size_t bsize = mi_page_usable_block_size(page);
|
|
531
|
+
// #if (MI_STAT>1)
|
|
532
|
+
// const size_t usize = mi_page_usable_size_of(page, block);
|
|
533
|
+
// mi_heap_stat_decrease(heap, malloc_requested, usize);
|
|
534
|
+
// #endif
|
|
535
|
+
if (bsize <= MI_MEDIUM_OBJ_SIZE_MAX) {
|
|
536
|
+
mi_heap_stat_decrease(heap, malloc_normal, bsize);
|
|
537
|
+
#if (MI_STAT > 1)
|
|
538
|
+
mi_heap_stat_decrease(heap, malloc_bins[_mi_bin(bsize)], 1);
|
|
539
|
+
#endif
|
|
540
|
+
}
|
|
541
|
+
//else if (bsize <= MI_LARGE_OBJ_SIZE_MAX) {
|
|
542
|
+
// mi_heap_stat_decrease(heap, malloc_large, bsize);
|
|
543
|
+
//}
|
|
544
|
+
else {
|
|
545
|
+
mi_heap_stat_decrease(heap, malloc_huge, bsize);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
#else
|
|
549
|
+
static void mi_stat_free(const mi_page_t* page, const mi_block_t* block) {
|
|
550
|
+
MI_UNUSED(page); MI_UNUSED(block);
|
|
551
|
+
}
|
|
552
|
+
#endif
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
// Remove guard page when building with MI_GUARDED
|
|
556
|
+
#if MI_GUARDED
|
|
557
|
+
static void mi_block_unguard(mi_page_t* page, mi_block_t* block, void* p) {
|
|
558
|
+
MI_UNUSED(p);
|
|
559
|
+
mi_assert_internal(mi_block_ptr_is_guarded(block, p));
|
|
560
|
+
mi_assert_internal(mi_page_has_aligned(page));
|
|
561
|
+
mi_assert_internal((uint8_t*)p - (uint8_t*)block >= (ptrdiff_t)sizeof(mi_block_t));
|
|
562
|
+
mi_assert_internal(block->next == MI_BLOCK_TAG_GUARDED);
|
|
563
|
+
|
|
564
|
+
const size_t bsize = mi_page_block_size(page);
|
|
565
|
+
const size_t psize = _mi_os_page_size();
|
|
566
|
+
mi_assert_internal(bsize > psize);
|
|
567
|
+
mi_assert_internal(_mi_page_segment(page)->allow_decommit);
|
|
568
|
+
void* gpage = (uint8_t*)block + bsize - psize;
|
|
569
|
+
mi_assert_internal(_mi_is_aligned(gpage, psize));
|
|
570
|
+
_mi_os_unprotect(gpage, psize);
|
|
571
|
+
}
|
|
572
|
+
#endif
|