Commit Graph

993 Commits

Author SHA1 Message Date
Duncan P. N. Exon Smith
5449852030 modules: Add explicit dependency on intrinsics_gen
`LLVM_ENABLE_MODULES` builds sometimes fail because `Intrinsics.td`
needs to regenerate `Instrinsics.h` before anyone can include anything
from the LLVM_IR module.  Represent the dependency explicitly to prevent
that.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239796 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-16 00:44:12 +00:00
Peter Collingbourne
7ffec838a2 Protection against stack-based memory corruption errors using SafeStack
This patch adds the safe stack instrumentation pass to LLVM, which separates
the program stack into a safe stack, which stores return addresses, register
spills, and local variables that are statically verified to be accessed
in a safe way, and the unsafe stack, which stores everything else. Such
separation makes it much harder for an attacker to corrupt objects on the
safe stack, including function pointers stored in spilled registers and
return addresses. You can find more information about the safe stack, as
well as other parts of or control-flow hijack protection technique in our
OSDI paper on code-pointer integrity (http://dslab.epfl.ch/pubs/cpi.pdf)
and our project website (http://levee.epfl.ch).

The overhead of our implementation of the safe stack is very close to zero
(0.01% on the Phoronix benchmarks). This is lower than the overhead of
stack cookies, which are supported by LLVM and are commonly used today,
yet the security guarantees of the safe stack are strictly stronger than
stack cookies. In some cases, the safe stack improves performance due to
better cache locality.

Our current implementation of the safe stack is stable and robust, we
used it to recompile multiple projects on Linux including Chromium, and
we also recompiled the entire FreeBSD user-space system and more than 100
packages. We ran unit tests on the FreeBSD system and many of the packages
and observed no errors caused by the safe stack. The safe stack is also fully
binary compatible with non-instrumented code and can be applied to parts of
a program selectively.

This patch is our implementation of the safe stack on top of LLVM. The
patches make the following changes:

- Add the safestack function attribute, similar to the ssp, sspstrong and
  sspreq attributes.

- Add the SafeStack instrumentation pass that applies the safe stack to all
  functions that have the safestack attribute. This pass moves all unsafe local
  variables to the unsafe stack with a separate stack pointer, whereas all
  safe variables remain on the regular stack that is managed by LLVM as usual.

- Invoke the pass as the last stage before code generation (at the same time
  the existing cookie-based stack protector pass is invoked).

- Add unit tests for the safe stack.

Original patch by Volodymyr Kuznetsov and others at the Dependable Systems
Lab at EPFL; updates and upstreaming by myself.

Differential Revision: http://reviews.llvm.org/D6094

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239761 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-15 21:07:11 +00:00
Rafael Espindola
3aef7761ac Don't indent inside a namespace. NFC.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239760 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-15 21:04:27 +00:00
Rafael Espindola
132c3549d9 Replace @ with the more common \. NFC.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239759 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-15 21:02:49 +00:00
Rafael Espindola
9e26836221 Don't repeat names in comments and start functions with a lower case letter.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239756 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-15 20:55:37 +00:00
Rafael Espindola
1456b12847 Cleanup the constructor of BitcodeReader. NFC.
Use the same argument names as the members.
Use default member initializes.

Extracted from a patch by Karl Schimpf.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239749 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-15 20:08:17 +00:00
Yaron Keren
bffcf0d1c9 Rangify several for loops in ValueEnumerator constructor.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239636 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-12 20:18:20 +00:00
Yaron Keren
923bd1da56 Rangify two for loops in BitcodeReader.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239627 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-12 18:13:20 +00:00
Filipe Cabecinhas
ce986b6bc0 Use early return idiom. NFC
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239228 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-06 20:44:53 +00:00
Filipe Cabecinhas
a3a2cab504 [BitcodeReader] Diagnose type mismatches with aliases
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238895 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-03 01:30:13 +00:00
Filipe Cabecinhas
287f68d654 [BitcodeReader] Check vector size before trying to create a VectorType
Bug found with AFL fuzz

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238891 91177308-0d34-0410-b5e6-96231b3b80d8
2015-06-03 00:05:30 +00:00
Filipe Cabecinhas
3b821159da [BitcodeReader] Change an assert to a call to a call to Error()
It's reachable from user input.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238633 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-30 00:17:20 +00:00
Benjamin Kramer
9589ff8949 Replace push_back(Constructor(foo)) with emplace_back(foo) for non-trivial types
If the type isn't trivially moveable emplace can skip a potentially
expensive move. It also saves a couple of characters.


Call sites were found with the ASTMatcher + some semi-automated cleanup.

memberCallExpr(
    argumentCountIs(1), callee(methodDecl(hasName("push_back"))),
    on(hasType(recordDecl(has(namedDecl(hasName("emplace_back")))))),
    hasArgument(0, bindTemporaryExpr(
                       hasType(recordDecl(hasNonTrivialDestructor())),
                       has(constructExpr()))),
    unless(isInTemplateInstantiation()))

No functional change intended.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238602 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-29 19:43:39 +00:00
Filipe Cabecinhas
1c0b496636 [BitcodeReader] Change assert to report_fatal_error
It can be triggered by user input.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238272 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-27 01:05:40 +00:00
Filipe Cabecinhas
316f9e05ce [BitstreamReader] Make sure the Array operand type is an encoding
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238269 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-27 00:48:43 +00:00
Filipe Cabecinhas
ba7ccd4201 clang-format a couple of lines
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238268 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-27 00:48:37 +00:00
Filipe Cabecinhas
c756772b8d [BitcodeReader] Make sure abbrev records have at least one operand (record code)
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238265 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-26 23:52:21 +00:00
Owen Anderson
13146c7e3b Add initial support for the convergent attribute.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238264 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-26 23:48:40 +00:00
Filipe Cabecinhas
1c74d4768a [BitcodeReader] Sanity check on Comdat ID
Shouldn't be an assert, since user input can trigger it.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238261 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-26 23:00:56 +00:00
Rafael Espindola
b9f5ce3a43 Simplify boolean conditional return statements.
Patch by Richard <legalize@xmission.com>

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238134 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-25 13:50:21 +00:00
Adrian Prantl
849c7601a0 IR / debug info: Add a DWOId field to DICompileUnit,
so DWARF skeleton CUs can be expression in IR. A skeleton CU is a
(typically empty) DW_TAG_compile_unit that has a DW_AT_(GNU)_dwo_name and
a DW_AT_(GNU)_dwo_id attribute. It is used to refer to external debug info.

This is a prerequisite for clang module debugging as discussed in
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-November/040076.html.
In order to refer to external types stored in split DWARF (dwo) objects,
such as clang modules, we need to emit skeleton CUs, which identify the
dwarf object (i.e., the clang module) by filename (the SplitDebugFilename)
and a hash value, the dwo_id.

This patch only contains the IR changes. The idea is that a CUs with a
non-zero dwo_id field will be emitted together with a DW_AT_GNU_dwo_name
and DW_AT_GNU_dwo_id attribute.

http://reviews.llvm.org/D9488
rdar://problem/20091852

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237949 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-21 20:37:30 +00:00
Filipe Cabecinhas
bf27e11e02 [BitcodeReader] Error out if we read an invalid function argument type
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237650 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-19 01:21:06 +00:00
Filipe Cabecinhas
c3ccd67d72 [BitcodeReader] It's a malformed block if CodeLenWidth is too big
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237646 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-19 00:34:17 +00:00
Filipe Cabecinhas
b2bf278152 [BitcodeReader] Make sure the type of the inserted value matches the type of the aggregate at those indices
Bug found with AFL-fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237628 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-18 22:27:11 +00:00
Filipe Cabecinhas
70a2c7260a Extract the load/store type verification to a separate function.
Summary:
Added isLoadableOrStorableType to PointerType.

We were doing some checks in some places, occasionally assert()ing instead
of telling the caller. With this patch, I'm putting all type checking in
the same place for load/store type instructions, and verifying the same
thing every time.

I also added a check for load/store of a function type.

Applied extracted check to Load, Store, and Cmpxcg.

I don't have exhaustive tests for all of these, but all Error() calls in
TypeCheckLoadStoreInst are being tested (in invalid.test).

Reviewers: dblaikie, rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9785

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237619 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-18 21:48:55 +00:00
Filipe Cabecinhas
ddf553bb8d [BitcodeReader] Don't allow INSERTVAL/EXTRACTVAL with 0 indices
This would trigger an assertion later.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237494 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-16 00:33:12 +00:00
Filipe Cabecinhas
6bde794d52 Remove redundant checks. NFC
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237488 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-15 23:57:13 +00:00
Eric Christopher
1bef1cdd92 While in GlobalValue fix the function(s) that don't follow the
naming convention and update users.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237461 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-15 18:20:14 +00:00
David Blaikie
66583e4917 [opaque pointer type] Explicit pointee type for GEPOperator/GEPConstantExpr.
Also a couple of other changes to avoid use of
PointerType::getElementType here & there too.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236799 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-08 00:42:26 +00:00
Duncan P. N. Exon Smith
6cc81efe93 Bitcode: Set LastDL after writing DebugLocs
Somehow I dropped this in r233585, and we haven't had `DEBUG_LOC_AGAIN`
records since.  Add it back.  Also tests that the output assembly looks
okay.

Fixes PR23436.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236661 91177308-0d34-0410-b5e6-96231b3b80d8
2015-05-06 22:51:12 +00:00
Filipe Cabecinhas
deedba2a36 Don't overflow GCTable
Summary: Bug found with AFL fuzz.

Reviewers: rafael, dexonsmith

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9361

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236200 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-30 04:09:41 +00:00
Filipe Cabecinhas
8b2199e2a2 Make sure Op->getType() is a PointerType before we cast<> it.
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236193 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-30 01:13:31 +00:00
Filipe Cabecinhas
a607be94ca Make sure we don't resize(0) when we get a fwdref with Idx == UINT_MAX
Make it an error instead.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236190 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-30 00:52:42 +00:00
David Blaikie
39e7388a19 [opaque pointer type] Pass GlobalAlias the actual pointer type rather than decomposing it into pointee type + address space
Many of the callers already have the pointer type anyway, and for the
couple of callers that don't it's pretty easy to call PointerType::get
on the pointee type and address space.

This avoids LLParser from using PointerType::getElementType when parsing
GlobalAliases from IR.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236160 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 21:22:39 +00:00
Duncan P. N. Exon Smith
e56023a059 IR: Give 'DI' prefix to debug info metadata
Finish off PR23080 by renaming the debug info IR constructs from `MD*`
to `DI*`.  The last of the `DIDescriptor` classes were deleted in
r235356, and the last of the related typedefs removed in r235413, so
this has all baked for about a week.

Note: If you have out-of-tree code (like a frontend), I recommend that
you get everything compiling and tests passing with the *previous*
commit before updating to this one.  It'll be easier to keep track of
what code is using the `DIDescriptor` hierarchy and what you've already
updated, and I think you're extremely unlikely to insert bugs.  YMMV of
course.

Back to *this* commit: I did this using the rename-md-di-nodes.sh
upgrade script I've attached to PR23080 (both code and testcases) and
filtered through clang-format-diff.py.  I edited the tests for
test/Assembler/invalid-generic-debug-node-*.ll by hand since the columns
were off-by-three.  It should work on your out-of-tree testcases (and
code, if you've followed the advice in the previous paragraph).

Some of the tests are in badly named files now (e.g.,
test/Assembler/invalid-mdcompositetype-missing-tag.ll should be
'dicompositetype'); I'll come back and move the files in a follow-up
commit.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236120 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 16:38:44 +00:00
Filipe Cabecinhas
fe7b873743 Use an "early return" idiom for the error case. NFC
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236080 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 02:36:08 +00:00
Filipe Cabecinhas
99ebc9e004 Check that we have a valid PointerType element type before calling get()
Same as r236073 but for PointerType.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236079 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 02:27:28 +00:00
Filipe Cabecinhas
5c9b6dbb73 Use the ArrayType member function for array element types.
ArrayType and StructType accept the same types, so no test.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236078 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 02:27:21 +00:00
Filipe Cabecinhas
7b30f32d3d Turn an assert into report_fatal_error since it's reachable based on user input
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236076 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 01:58:31 +00:00
Filipe Cabecinhas
3b4a565b8a Make sure that isValidElementType(Type) before calling {Array,Struct}Type::get(Type)
Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236073 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-29 01:27:01 +00:00
Filipe Cabecinhas
7acbf56112 Relax an assert when there's a type mismatch in forward references
Summary:
We don't seem to need to assert here, since this function's callers expect
to get a nullptr on error. This way we don't assert on user input.

Bug found with AFL fuzz.

Reviewers: rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9308

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@236027 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-28 20:18:47 +00:00
David Blaikie
e48ac32ea2 [opaque pointer type] Encode the allocated type of an alloca rather than its pointer result type.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235998 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-28 16:51:01 +00:00
David Blaikie
974d5d32c8 [opaque pointer type] Encode the pointee type in the bitcode for 'cmpxchg'
As a space optimization, this instruction would just encode the pointer
type of the first operand and use the knowledge that the second and
third operands would be of the pointee type of the first. When typed
pointers go away, this assumption will no longer be available - so
encode the type of the second operand explicitly and rely on that for
the third.

Test case added to demonstrate the backwards compatibility concern,
which only comes up when the definition of the second operand comes
after the use (hence the weird basic block sequence) - at which point
the type needs to be explicitly encoded in the bitcode and the record
length changes to accommodate this.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235966 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-28 04:30:29 +00:00
David Blaikie
d455682f39 [opaque pointer type] encode the pointee type of global variables
Use a few extra bits in the const field (after widening it from a fixed
single bit) to stash the address space which is no longer provided by
the type (and an extra bit in there to specify that we're using that new
encoding).

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235911 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-27 19:58:56 +00:00
Duncan P. N. Exon Smith
ae3211466a IR: Add assembly/bitcode support for function metadata attachments
Add serialization support for function metadata attachments (added in
r235783).  The syntax is:

    define @foo() !attach !0 {

Metadata attachments are only allowed on functions with bodies.  Since
they come before the `{`, they're not really part of the body; since
they require a body, they're not really part of the header.  In
`LLParser` I gave them a separate function called from `ParseDefine()`,
`ParseOptionalFunctionMetadata()`.

In bitcode, I'm using the same `METADATA_ATTACHMENT` record used by
instructions.  Instruction metadata attachments are included in a
special "attachment" block at the end of a `Function`.  The attachment
records are laid out like this:

    InstID (KindID MetadataID)+

Note that these records always have an odd number of fields.  The new
code takes advantage of this to recognize function attachments (which
don't need an instruction ID):

    (KindID MetadataID)+

This means we can use the same attachment block already used for
instructions.

This is part of PR23340.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235785 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-24 22:04:41 +00:00
David Blaikie
c5b1f0a49d [opaque pointer type] bitcode: add explicit callee type to invoke instructions
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235735 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-24 18:06:06 +00:00
Filipe Cabecinhas
45a69610a7 [BitcodeReader] Fix asserts when we read a non-vector type for insert/extract/shuffle
Added some additional checking for vector types + tests.

Bug found with AFL fuzz.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235710 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-24 11:30:15 +00:00
David Blaikie
93a23a3bd4 Recommit r235458: [opaque pointer type] Avoid using PointerType::getElementType for a few cases of CallInst
(reverted in r235533)

Original commit message:

"Calls to llvm::Value::mutateType are becoming extra-sensitive now that
instructions have extra type information that will not be derived from
operands or result type (alloca, gep, load, call/invoke, etc... ). The
special-handling for mutateType will get more complicated as this work
continues - it might be worth making mutateType virtual & pushing the
complexity down into the classes that need special handling. But with
only two significant uses of mutateType (vectorization and linking) this
seems OK for now.

Totally open to ideas/suggestions/improvements, of course.

With this, and a bunch of exceptions, we can roundtrip an indirect call
site through bitcode and IR. (a direct call site is actually trickier...
I haven't figured out how to deal with the IR deserializer's lazy
construction of Function/GlobalVariable decl's based on the type of the
entity which means looking through the "pointer to T" type referring to
the global)"

The remapping done in ValueMapper for LTO was insufficient as the types
weren't correctly mapped (though I was using the post-mapped operands,
some of those operands might not have been mapped yet so the type
wouldn't be post-mapped yet). Instead use the pre-mapped type and
explicitly map all the types.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235651 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-23 21:36:23 +00:00
Filipe Cabecinhas
0236022390 Be more strict about the operand for the array type in BitcodeReader
Summary: Bug found with AFL fuzz.

Reviewers: rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9016

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235596 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-23 13:38:21 +00:00
Filipe Cabecinhas
81f9bd3e19 Verify sizes when trying to read a BitcodeAbbrevOp
Summary:
Make sure the abbrev operands are valid and that we can read/skip them
afterwards.

Bug found with AFL fuzz.

Reviewers: rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D9030

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@235595 91177308-0d34-0410-b5e6-96231b3b80d8
2015-04-23 13:25:35 +00:00