libredwg / libredwg Goto Github PK
View Code? Open in Web Editor NEWOfficial mirror of libredwg. With CI hooks and nightly releases. PR's ok
Home Page: https://savannah.gnu.org/projects/libredwg/
License: GNU General Public License v3.0
Official mirror of libredwg. With CI hooks and nightly releases. PR's ok
Home Page: https://savannah.gnu.org/projects/libredwg/
License: GNU General Public License v3.0
LibreDWG - free implementation of the DWG file format LibreDWG is a free C library to read and write DWG files. This program is part of the GNU project, released under the aegis of GNU. It is licensed under the terms of the GNU General Public License version 3 (or at you option any later version). DWG is a file format created in the 70's for the emerging CAD applications. Currently it is the native file format of AutoCAD, a proprietary CAD program developed by AutoDesk. LibreDWG is a fork from LibDWG due to its usage of Esperanto, which we think is not the best strategy for a free software project which aims to get lots of contributors. LibreDWG is written in English. At the moment our decoder (i.e. reader) is done, it can read all DWG versions, just some very advanced R2010+ objects fail to read and are skipped over. The writer is good enough for R1.4 - R2000. Among the example applications we wrote using LibreDWG is a reader, a writer, a rewriter (i.e. saveas), an initial SVG and Postscript conversion, dxf and json converters, dwggrep to search for text, and dwglayer to print the list of layers. More are in the pipeline. Please contact us if you want to help. The strings API is UTF-8 (WTF8 really, Windows UCS-2 has no surrogate pairs), and encodes to the internal 8-bit or UCS-2 strings, depending on the DWG version. Older DWG's are encoded in ~30 codepages, which we convert to unicode/UTF-8. We also maintain a diff document for our internal fixed ODA-5.4.1 spec at doc/ODA-5.4.2-libredwg-diff.pdf For contact file a ticket or email the package maintainers: Reini Urban <rurban AT cpan.org> The now inactive founders and previous maintainers were: Felipe Corrêa da Silva Sanches <juca AT members.fsf.org> Rodrigo Rodrigues da Silva <pitanga AT members.fsf.org> Hardeep Singh Rai <hardeep.rai AT gmail DOT com> If you are looking for general information about the project, check our website: http://www.gnu.org/software/libredwg/ == Building and installing the library == You need the following dependencies: - Basic development tools (a C99 compiler like gcc/clang, make, autoconf, automake and libtool) Optionally: - libiconv: optional codepage conversion. without it's just a bit slower. - libmimalloc: faster memory allocation, but usually not worth the hassle. - pslib for dwg2ps: http://pslib.sourceforge.net/doc/pslib.html - pcre2 with 8bit and 16bit libraries for dwggrep regexp support. - gperf to update static hashes for several API's Only needed when you added objects or changed the dwg.spec significantly - cmake, ninja - TeXinfo for building the docs - SWIG 1.7+ - Python 2.7 or 3.x development headers (debian: python-dev; yum: python-devel) and the libxml2 python bindings. - Perl 5 for the perl bindings - doxygen to generate the reference manual - jq to check json validity, and as dwgfilter backend - shellcheck to check shell scripts - rpmlint to check the spec validity - jinq with some svg11 relaxng to check SVG validity. LaTeXML used to have a broken svg11-basic.rng. If so the zip from http://yupotan.sppd.ne.jp/relax-ng/svg11/ is correct. Needs to be installed into /usr/local/share/relaxng/svg11/ sudo unzip ~/Downloads/svg11-relaxng-20060604.zip -d /usr/local/share/relaxng/ On Ubuntu I needed: apt install jing libjaxp1.3-java libbatik-java libavalon-framework-java - mapbox/geojsonhint as geojson linter npm install -g @mapbox/geojsonhint - geojson-validation as 2nd geojson fallback linter npm install -g geojson-validation - shfmt to format shell scripts - clang-format to format the C source code - clang-tidy to check source code - valgrind to find leaks and memory bugs - timeout to help tests with large or hanging DWG's - GNU parallel to speed up special tests (not the moreutils parallel!) - picat to find unknown fields, a better prolog. http://picat-lang.org/ See INSTALL for generic instructions. Basically, you do: $ sh ./autogen.sh (if you checked out the source code from git) $ ./configure [--enable-trace] [--disable-write] [--disable-shared] $ make $ make check $ sudo make install This builds and installs various files in the "installation dirs": $libdir ($exec_prefix/lib) -- library files (libredwg.*) $includedir ($prefix/include) -- dwg.h dwg_api.h $libdir/pkgconfig -- libredwg.pc $infodir ($datarootdir/info) -- LibreDWG.info Use "./configure --help" to see a full list of options you can use to customize the installation dirs. Other options recognized by configure are: --enable-release Recommended for packagers and fuzzers. Disables all features which will not be enabled in official tarball releases. Like skipping unstable DWG features or objects, unknown DWG versions and objects. --enable-trace Enable runtime tracing (default: no). When enabled, the environment variable LIBREDWG_TRACE is consulted on the first decode/encode attempt. Its value is an integer: 0 (no output) through 9 (full verbosity). Most tools do support a --verbosity|-v flag instead. --with-dxf-precision=rfc How many after-comma places in DXF doubles. 6 is the recommended value (e.g. use rfc), max and the default is 16. --with-geojson-precision=rfc How many after-comma places in GeoJSON doubles. 6 is the recommended value by RFC 7946, max and the default is 16. --disable-write Disable DWG write support (default: no). Write support only works for earlier versions until r2004. Rewriting most DWG's <= r2004 usually works fine. --disable-bindings Disable SWIG bindings for python and perl5. --disable-dxf Disables all in and out modules: DXF, DXFB, JSON, GeoJSON. --disable-json Disables the json in and out modules: JSON, GeoJSON. --disable-python Disable python bindings and tests. Related: --enable-python=python3.6 Enforce a specific version. --enable-debug Activates support for unstable classes. For testing only. --enable-gcov Activates support for GNU gcov, test coverage reporting. --with-perl-install=vendor Where to install the perl bindings: vendor,arch,yes,no,site. Default is perl-install=site == Windows == See the following scripts how we build on Windows: * .github/workflows/main.yml: via msys/autotools, or cmake. gcc, clang-cl or VS2019. * build-aux/smoke.sh: cross-compilation recipes * build-aux/msys2.bat: msys2 deps * .appveyor.yml: windows smoker We do support mingw, clang-cl and now also Visual Studio 2019 via cmake. stdint.h and inttypes.h must be available. Pre-compiled Windows binaries are here: https://github.com/LibreDWG/libredwg/releases == Example usage of the library == The programs and examples directories contains some application code that uses our lib: * dwgread -- A DWG reader supporting various output formats, such as JSON, DXF, DXFB, GeoJSON. Later also YAML, XML/OGR, GPX, SVG, PS. * dwgwrite -- A DWG writer supporting various input formats, such as DXF, DXFB, JSON. GeoJSON, YAML, XML/OGR, GPX are under construction. * dwg2dxf -- Converts a DWG to a DXF (ascii or binary, minimal or full), optionally under a different version. About 90% coverage. * dxf2dwg -- Converts a ascii or binary DXF to a DWG (r2000 only so far). About 80% coverage. * dwglayers -- Prints the list of layers in a DWG. Optionally with --extnames * dwggrep -- Searches DWG files for a text string, via regular expressions. * dwg2ps -- Opens a DWG file and outputs an PostScript file. This code depends on the PSlib library. On Debian-based systems this is usually available as a package named pslib-dev. This is very limited so far. * dwgfilter -- Applies JSON filters via JQ. Either as structured grep, or to mass change certain values. * dwg2SVG -- Opens a DWG file and outputs an SVG (Scalable Vector Graphics) file. SVG is a W3C standard for 2d vector graphics. You can open these files on several free software tools. We recommend Inkscape, a free software vector graphics editor. The dwg2SVG program will not handle 3d content from DWG since SVG only supports 2-dimensional images. Handles only some entities. * dwgbmp -- Extracts the bmp thumbnail of a dwg file when it is available. * dwgadd -- the easiest way to create DWG's (or DXF, JSON) from scratch or add entities to an existing DWG. It accepts a very simple file with commands to create entities or objects and set its properties. * dwgrewrite -- Reads a DWG, writes it back under a different name and optionally under a different version (default r2000), and re-reads it back for confirmation. * load_dwg -- This is a skeleton code, reading the DWG and adding an entity. Look there if you want to have a quickly glance on how to use the library. * dwg2svg2 -- Another example how to use the DWG API, bypassing direct access to the DWG struct. * xmlsuite -- an extensive example library to use XML to compare against prepared features is in the test/xmlsuite directory. It also features code to output entities in XML, but does not use the python bindings. Copyright (C) 2009, 2010, 2015, 2018-2024 Free Software Foundation, Inc. This library is free software, licensed under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
In some reasons, 2 pointers refer in single object, and free this object twice.
Object is created in dwg_decode_handleref_with_code
and stored in dwg->object_ref
array. Then it return from function and assigned to object's subentity
field.
In dwg_free
at first some object is destroyed with his subentity
, and then all object_ref
is destroyed with thouse subentity
one more time.
Can you help me fix this bug? Maybe you are know how this problem can be solved?
See #27
An entity with color flag 0x40 needs to decode the DBCOLOR ref.
testcases: 2004/dbcolor and 2004/CascoUrbano
There are a bunch of unknown classes for entities, if this is something I can help with please let me know and point me in the direction of the files I need to edit
Warning: Unknown Class object 541 AEC_DISP_PROPS_MASS_ELEM_MODEL (0x81)
Warning: Unknown Class object 542 AEC_DISP_REP_MASS_GROUP_MODEL (0x81)
Warning: Unknown Class object 544 AEC_DISP_REP_MASS_ELEM_MODEL (0x81)
Warning: Unknown Class object 545 AEC_DISP_REP_MASS_GROUP_PLAN (0x81)
Warning: Unknown Class object 543 AEC_DISP_PROPS_MASS_GROUP (0x81)
Warning: Unknown Class object 546 AEC_DISP_REP_CLIP_VOLUME_MODEL (0x81)
Warning: Unknown Class object 547 AEC_DISP_PROPS_CLIP_VOLUME (0x81)
Warning: Unknown Class object 548 AEC_DISP_REP_CLIP_VOLUME_RESULT (0x81)
Warning: Unknown Class object 549 AEC_DISP_REP_ANCHOR_EXT_TAG_TO_ENT (0x81)
Warning: Unknown Class object 550 AEC_DISP_PROPS_ENT (0x81)
Warning: Unknown Class object 551 AEC_DISP_REP_ANCHOR (0x81)
Warning: Unknown Class object 552 AEC_DISP_REP_CLIP_VOLUME_RESULT_SUBDIV (0x81)
Warning: Unknown Class object 553 AEC_DISP_PROPS_CLIP_VOLUME_RESULT (0x81)
Warning: Unknown Class object 554 AEC_DISP_REP_ANCHOR_TAG_TO_ENT (0x81)
Warning: Unknown Class object 555 AEC_DISP_REP_ANCHOR_ENT_TO_NODE (0x81)
Warning: Unknown Class object 556 AEC_DISP_REP_2D_SECTION (0x81)
Warning: Unknown Class object 557 AEC_DISP_PROPS_2D_SECTION (0x81)
Warning: Unknown Class object 558 AEC_DISP_REP_CLIP_VOLUME_PLAN (0x81)
Warning: Unknown Class object 559 AEC_DISP_REP_POLYGON_TRUECOLOUR (0x81)
Warning: Unknown Class object 560 AEC_DISP_PROPS_POLYGON_TRUECOLOUR (0x81)
Warning: Unknown Class object 561 AEC_DISP_REP_ENT_REF (0x81)
Warning: Unknown Class object 562 AEC_DISP_PROPS_ENT_REF (0x81)
Warning: Unknown Class object 563 AEC_DISP_REP_POLYGON_MODEL (0x81)
Warning: Unknown Class object 564 AEC_DISP_PROPS_POLYGON_MODEL (0x81)
Warning: Unknown Class object 565 AEC_DISP_REP_EDITINPLACEPROFILE (0x81)
Warning: Unknown Class object 566 AEC_DISP_PROPS_EDITINPLACEPROFILE_MODEL (0x81)
Warning: Unknown Class object 567 AEC_DISP_REP_MATERIAL (0x81)
Warning: Unknown Class object 568 AEC_DISP_PROPS_MATERIAL (0x81)
Warning: Unknown Class object 569 AEC_DISP_REP_MVBLOCK_REF (0x81)
Warning: Unknown Class object 570 AEC_DISP_REP_MASKBLOCK_REF (0x81)
Warning: Unknown Class object 571 AEC_DISP_PROPS_MASKBLOCK (0x81)
Warning: Unknown Class object 572 AEC_DISP_REP_DISPLAYTHEME (0x81)
Warning: Unknown Class object 573 AEC_DISP_PROPS_DISPLAYTHEME (0x81)
Warning: Unknown Class object 574 AEC_DISP_REP_LAYOUT_GRID2D (0x81)
Warning: Unknown Class object 575 AEC_DISP_PROPS_LAYOUT_GRID2D (0x81)
Warning: Unknown Class object 576 AEC_DISP_REP_LAYOUT_GRID3D (0x81)
Warning: Unknown Class object 577 AEC_DISP_PROPS_LAYOUT_GRID3D (0x81)
Warning: Unknown Class object 578 AEC_DISP_REP_LAYOUT_CURVE (0x81)
Warning: Unknown Class object 579 AEC_DISP_PROPS_LAYOUT_CURVE (0x81)
Warning: Unknown Class object 580 AEC_DISP_REP_MVBLOCK_REF_MODEL (0x81)
Warning: Unknown Class object 581 AEC_DISP_REP_SLICE (0x81)
Warning: Unknown Class object 582 AEC_DISP_PROPS_SLICE (0x81)
Warning: Unknown Class object 583 AEC_DISP_REP_CEILING_GRID (0x37d)
Warning: Unknown Class object 584 AEC_DISP_REP_CURTAIN_WALL_LAYOUT_PLAN (0x81)
Warning: Unknown Class object 585 AEC_DISP_PROPS_GRID_ASSEMBLY_PLAN (0x81)
Warning: Unknown Class object 586 AEC_DISP_REP_COLUMN_GRID (0x81)
fix the {DY}LD_LIBRARY_PATH and LDDLFLAGS.
and it clashes with an installed (older) dwg.h
Is it possible to extract xref information from a dwg ?
wrong obj_string_stream
on certain fixed types without strings do not call obj_string_stream() at all. add a new obj_has_strings(type).
I've add a --enable-python=<python path>
flag for a --enable-python=python3.6
cfg arg, but the probe fails.
I've been converting DWG files made with some quite old version of AutoCAD, like 2004 or even 2002, I'm not sure, and discovered that the library (I've tried recently released v0.6) segfaults on some of them inside dwg_model_space_ref()
in dwg.c
, apparently while accessing dwg->header_vars.BLOCK_RECORD_PSPACE
(stack trace is trivial so I'd waive it). This happens both on i386 and amd64.
Example of problematic file.
Low precision DXF. Or call it --basic
, but there -b
is already taken to --binary
.
Like the --minimal
flag, but output more like with dxfrw
. i.e. no SUBCLASS markers and handles, no dictionaries, reactors, ...
Creates smaller DXF files, and should still be readable by acad.
Looked at this again, it is wrong. Most checks needs to be versioned, not some arbitrary --low or minimal check.
TODO: down-conversions from unsupported entities on older DXF versions:
Since r13: Entities: LWPOLYLINE, HATCH, SPLINE, LEADER, DIMENSION, MTEXT, IMAGE,
BLOCK_RECORD.
Table BLOCK_RECORD.
add CLASSES for those
handle 5, 100, 105
non-all caps table names.
Since r14: handle 330
Either the last member of the array needs to be NULL, or we need to return the count.
Since we don't want to change the API, we NULL-terminate it.
We also need to guard from an empty BLOCK_HEADER argument
Missing config.h file?
Currently, the highest support is to reach this version?
someone, maybe CRC, is overwriting the Dwg_Struct after num_classes,
32bit only. with dwg2svg2 only.
CRC = 36953}, num_classes = 4,
dwg_class = 0x8153100, num_objects = 61, object = 0x8158398, num_layers = 0,
num_entities = 12, num_object_refs = 154, object_ref = 0x8155b78, layer_control = 0x81532a0,
mspace_block = 0x8154ff0, pspace_block = 0x8156560,
=>
CRC = 65028}, num_classes = 3086986712,
dwg_class = 0xad9f3224, num_objects = 1336173547, object = 0x9059, num_layers = 4,
num_entities = 135606528, num_object_refs = 61, object_ref = 0x8158398,
layer_control = 0x0, mspace_block = 0xc, pspace_block = 0x9a,
CRC ... num_entities is wrong.
dxf and json out need to treat some binary data different than text.
e.g. encode chars as %02x
json also needs to encode unprintable chars via +U
and escape \
properly.
either add a FIELD_TB to the spec or check the dxf code in FIELD_T
in DXF we already have VALUE_BINARY
travis (ubuntu) make distcheck:
make[3]: *** No rule to make target
libredwg.py', needed by distdir'. Stop.
See e.g. https://travis-ci.org/LibreDWG/libredwg/jobs/377595525
Obviously a failing SWIG probe or rule.
This prevents us from generating binary releases via travis. Which is not important, just nice to have.
Works fine on debian testing, darwin and windows.
find a simple POSIX way for this makefile (i.e. BSD make)
In principle like osmfilter, but with a sane query expression language.
Something like XPath or JSONPath with the dot. notation seem to be the best fit.
/
or //
is unneeded.By default pure, only display the result of the filter query.
It also needs to handle destructive changes: --delete and --keep for simple boolean queries
and maybe also changes (renames, transform) by assignment ops (+=) or s///.
depends on: #59
I have just compiled the lib, tried to load in a 2018 dwg file, and it outputs the following:
ERROR: This version of LibreDWG is only capable of safely decoding version R13-R2007 (code: AC1012-AC1021) DWG files.
Support for this version is still experimental. We don't decode all objects yet.
It will probably crash and/or give you invalid output.
ERROR: bit_read_BD: unexpected 2-bit code: '11'
ERROR: bit_read_BD: unexpected 2-bit code: '11'
ERROR: bit_read_BD: unexpected 2-bit code: '11'
ERROR: bit_read_BL: unexpected 2-bit code: '11'
Warning: Invalid handle pointer code 14
ERROR: Invalid handle-reference, longer than 4 bytes: 13.12.0
ERROR: Could not read handleref in the header variables section
ERROR: Invalid handle-reference, longer than 4 bytes: 5.6.0
ERROR: Could not read handleref in the header variables section
Warning: dwg_decode_handleref_with_code: Missing obj arg
Segmentation fault: 11
Hi, during conversion from dwg to dxf, there is wrong polyline coordinates. such as :
Thanks for help.
ORİGİNAL :
AcDbPolyline
90
4
70
129
43
0.0
10
-10.0
20
50.0
10
-10.0
20
60.0
10
0.0
20
60.0
10
0.0
20
50.0
exported by libredwg :
AcDbPolyline
90
4
70
1
10
-10.00000000000000
20
50.00000000000000
10
-10.00000000000000
20
60.00000000000000
10
0.0
20
-10.00000000000000 (must be 60)
10
0.0
20
50.00000000000000
I have problems decoding hatch with gradient in these files v2004 :
Can you please take a look if the spec is correct? Strangely the same files converted to version 2000 or 2007 open fine.
When running the command dwg2dxf test.dwg
on the .dwg sent to @rurban you get the following output
Warning: Object handle not found, 80 in 11073 objects
Warning: Object handle not found, 208 in 11073 objects
Warning: Object handle not found, 208 in 11073 objects
Warning: Object handle not found, 82 in 11073 objects
Writing DXF file test.dxf
Segmentation fault (core dumped)
When opening the resulting dxf in librecad it recognises some of the layers but no lines or any other drawing elements
When running the dwglayers
on the .dwg sent to @rurban there is no output (no segfult) it just exits
we have to jump through absurd hurdles in the API to get around that.
the parent
points to the _dwg_object_{entity, object}
, which points via the object
field to the _dwg_object
.
But beware that adding objects (realloc) moves and invalidates all internal cross pointers to Dwg_Object*, but not Dwg_Object_OBJECT*. Those are not realloced. Also not the object substructs.
They only problem I see are the dwg_{obj,ent}_obj->object links to the dwg_object*.
They need to be replaced by an objid.
Either scan the objects twice for the final size (but then we cannot add objects later, when writing), or make the parent link a handle or objid index.
Also when adding objects and a realloc happened, we need to re-resolve all handles/links. this btw is a release blocker, as we already added the add API.
for better performance alloc in bigger chunks, so we can skip the scan most of the times.
dwg_add needs to trigger a rescan flag btw.
Need to study the handles.
So far I disabled XRECORD dxf output
It's required for interfacing dynamic languages to provide a better dynamic API, and for the importers, a precompiled list or hash of all known elements, objects and subtypes with all its properties.
These can be generated via processing the dwg.h or dwg.spec into gperf hashes or arrays.
The needed info per field would be: name, type, offsetof(), (dxf).
Then we could also implement a dwgfilter program (#64), which allows filtering on user-defined, dynamic objects and it's properties. e.g. dwglayer, dwgxrefs, ...
analog to osmfilter
we could also get rid of the massively big and unmaintainable dwg_api functions, replacing it with the dynamic versions, separated by type. and add a reflective api, e.g. return the VERTEX_2D fields, the type of the VERTEX_3D.point field, ...
With large DWG's with large offsets from handles, some offsets were misrepresented due to underflow. The last byte (4 bits actually) was not read.
MC:
Read 1 modular char (max 5 bytes, signed).
Read bytes until the high bit of the byte is 0, drop the highest bit and pad with 0.
If the last byte has 0x40 set, it's negative. (since the 0x80 bit is dropped, 0x40 becomes the highest bit then)
Since the result is int32_t (4 byte) but there needs to be the high/follow bit set,
the stream can be max 5 byte long (5*7 = 35 bit)
10000000 10000000 10000000 10000000 00000100
=> 0000000 0000000 0000000 0000000 0000100 (5*7 = 35)
=> 00001000 00000000 00000000 00000000 (4*8 = 32)
With 4 byte only 4*7=28 bit can be represented, the highest 4 (from 32) are missing for large offsets >= 0x1000000 (0b0001000000000000000000000000)
Detected and fixed by @DenisPryt in #65
The very same error came originally from libdwg, and is also present in all other open source dwg libs:
libdwg, libdxfrw, pythoncad
I found another interesting issue with decoding handles and offsets for objects :
2004.zip
I may be wrong but it looks like for long handle address ModularChar reading can use more than 4 bytes, up to 8. Although the handles are read, some section pages contains large values that are not fully decoded and all handle references from header to block controls (layers, etc.) are not matching.
nobody else names it SHAPEFILE, only the ODA.
dxf names it STYLE and $TEXTSTYLE,
AutoCAD names it AcDbTextStyleTable,
libdxfrw names it STYLE and TEXTSTYLE
When open the crafted dwg
file , it could tigger double free
in dwg2svg2
Let's see the program error output
15:20 haclh@ubuntu:examples $ ./dwg2svg2 dfree_poc_155
......................................................................
......................................................................
......................................................................
=================================================================
*** Error in `./dwg2svg2': double free or corruption (fasttop): 0x0000000001336430 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f18b82547e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f18b825d37a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f18b826153c]
./dwg2svg2[0x499e0b]
./dwg2svg2[0x49a31a]
./dwg2svg2[0x4a18e9]
./dwg2svg2[0x4a239d]
./dwg2svg2[0x40d13f]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f18b81fd830]
./dwg2svg2[0x40d3a9]
======= Memory map: ========
00400000-00569000 r-xp 00000000 08:10 1140093 /home/haclh/vmdk/fuzz_workplace/libredwg-0.5.1048/examples/dwg2svg2
00768000-00769000 r--p 00168000 08:10 1140093 /home/haclh/vmdk/fuzz_workplace/libredwg-0.5.1048/examples/dwg2svg2
00769000-0076a000 rw-p 00169000 08:10 1140093 /home/haclh/vmdk/fuzz_workplace/libredwg-0.5.1048/examples/dwg2svg2
0076a000-0076c000 rw-p 00000000 00:00 0
01319000-0135b000 rw-p 00000000 00:00 0 [heap]
7f18b3dea000-7f18b3e00000 r-xp 00000000 08:01 1315919 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f18b3e00000-7f18b3fff000 ---p 00016000 08:01 1315919 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f18b3fff000-7f18b4000000 rw-p 00015000 08:01 1315919 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f18b4000000-7f18b4021000 rw-p 00000000 00:00 0
7f18b4021000-7f18b8000000 ---p 00000000 00:00 0
7f18b81dd000-7f18b839d000 r-xp 00000000 08:01 1366856 /lib/x86_64-linux-gnu/libc-2.23.so
7f18b839d000-7f18b859d000 ---p 001c0000 08:01 1366856 /lib/x86_64-linux-gnu/libc-2.23.so
7f18b859d000-7f18b85a1000 r--p 001c0000 08:01 1366856 /lib/x86_64-linux-gnu/libc-2.23.so
7f18b85a1000-7f18b85a3000 rw-p 001c4000 08:01 1366856 /lib/x86_64-linux-gnu/libc-2.23.so
7f18b85a3000-7f18b85a7000 rw-p 00000000 00:00 0
7f18b85a7000-7f18b86af000 r-xp 00000000 08:01 1315583 /lib/x86_64-linux-gnu/libm-2.23.so
7f18b86af000-7f18b88ae000 ---p 00108000 08:01 1315583 /lib/x86_64-linux-gnu/libm-2.23.so
7f18b88ae000-7f18b88af000 r--p 00107000 08:01 1315583 /lib/x86_64-linux-gnu/libm-2.23.so
7f18b88af000-7f18b88b0000 rw-p 00108000 08:01 1315583 /lib/x86_64-linux-gnu/libm-2.23.so
7f18b88b0000-7f18b88d6000 r-xp 00000000 08:01 1366854 /lib/x86_64-linux-gnu/ld-2.23.so
7f18b8aaf000-7f18b8ab3000 rw-p 00000000 00:00 0
7f18b8ad4000-7f18b8ad5000 rw-p 00000000 00:00 0
7f18b8ad5000-7f18b8ad6000 r--p 00025000 08:01 1366854 /lib/x86_64-linux-gnu/ld-2.23.so
7f18b8ad6000-7f18b8ad7000 rw-p 00026000 08:01 1366854 /lib/x86_64-linux-gnu/ld-2.23.so
7f18b8ad7000-7f18b8ad8000 rw-p 00000000 00:00 0
7fff6f0da000-7fff6f0fb000 rw-p 00000000 00:00 0 [stack]
7fff6f127000-7fff6f12a000 r--p 00000000 00:00 0 [vvar]
7fff6f12a000-7fff6f12c000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted
And the output with asan
15:20 haclh@ubuntu:examples $ ./dwg2svg2 dfree_poc_155
......................................................................
......................................................................
......................................................................
=================================================================
==101914==ERROR: AddressSanitizer: attempting double-free on 0x60400000dbd0 in thread T0:
#0 0x7f9dcd3e32ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
#1 0x642d83 in dwg_free_eed /home/haclh/workplace/libredwg-0.5.1048/src/free.c:283
#2 0x6513db in dwg_free_UNKNOWN_OBJ /home/haclh/workplace/libredwg-0.5.1048/src/dwg.spec:5437
#3 0x6513db in dwg_free_BLOCK_HEADER /home/haclh/workplace/libredwg-0.5.1048/src/dwg.spec:2177
#4 0x664f98 in dwg_free_object /home/haclh/workplace/libredwg-0.5.1048/src/free.c:471
#5 0x667d2a in dwg_free /home/haclh/workplace/libredwg-0.5.1048/src/free.c:640
#6 0x42d81d in test_SVG /home/haclh/workplace/libredwg-0.5.1048/examples/dwg2svg2.c:92
#7 0x42d81d in main /home/haclh/workplace/libredwg-0.5.1048/examples/dwg2svg2.c:482
#8 0x7f9dccfa182f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
#9 0x42de88 in _start (/home/haclh/workplace/libredwg-0.5.1048/examples/dwg2svg2+0x42de88)
0x60400000dbd0 is located 0 bytes inside of 40-byte region [0x60400000dbd0,0x60400000dbf8)
freed by thread T0 here:
#0 0x7f9dcd3e32ca in __interceptor_free (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x982ca)
#1 0x47ee9f in dwg_decode_eed /home/haclh/workplace/libredwg-0.5.1048/src/decode.c:2311
previously allocated by thread T0 here:
#0 0x7f9dcd3e379a in __interceptor_calloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x9879a)
#1 0x47e349 in dwg_decode_eed /home/haclh/workplace/libredwg-0.5.1048/src/decode.c:2304
SUMMARY: AddressSanitizer: double-free ??:0 __interceptor_free
==101914==ABORTING
According debuging, I found that When open the crafted dwg
file , dwg_free
could call dwg_decode_eed
, in dwg_free_object
first, it could call dwg_free_BLOCK_HEADER
to free a pointer (for example : 0x789430
)
void
dwg_free_object(Dwg_Object *obj)
{
switch (obj->type)
{
case DWG_TYPE_TEXT:
........................
........................
........................
case DWG_TYPE_BLOCK_HEADER:
dwg_free_BLOCK_HEADER(dat, obj);
break;
The backtrace are as below
f 0 7ffff77884f0 free
► f 1 49a1c4 dwg_free_BLOCK_HEADER.isra.7+68
f 2 4a18e9 dwg_free_object+1161
f 3 4a239d dwg_free+157
f 4 40d13f main+575
f 5 40d13f main+575
f 6 7ffff7724830 __libc_start_main+240
And then it could call dwg_free_BLOCK_HEADER
again , it could call dwg_free_eed
to free 0x789430
again.
The backtrace are as below
pwndbg> bt
#0 __GI___libc_free (mem=0x789430) at malloc.c:2934
#1 0x0000000000499e0b in dwg_free_eed (obj=0x7988e8, obj=0x7988e8) at free.c:283
#2 0x000000000049a31a in dwg_free_BLOCK_HEADER (obj=0x7988e8, _dat=<optimized out>) at dwg.spec:2285
#3 0x00000000004a18e9 in dwg_free_object (obj=0x7988e8) at free.c:471
#4 0x00000000004a239d in dwg_free (dwg=dwg@entry=0x769400 <g_dwg>) at free.c:640
#5 0x000000000040d13f in test_SVG (filename=<optimized out>) at dwg2svg2.c:92
#6 main (argc=argc@entry=2, argv=argv@entry=0x7fffffffe4c8) at dwg2svg2.c:479
#7 0x00007ffff7724830 in __libc_start_main (main=0x40cf00 <main>, argc=2, argv=0x7fffffffe4c8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe4b8) at ../csu/libc-start.c:291
#8 0x000000000040d3a9 in _start ()
The poc file
https://gitee.com/hac425/fuzz_data/blob/master/double_free_on_libredwg_155
When running over some dwgs from the same project I get the errors
Warning: Invalid handleref: wanted code 4, got (1.7.0)
ERROR: Invalid LTYPE.dash x 61
ERROR: Invalid LTYPE.dash x 215
ERROR: num_inserts [RC 0]: 136!
Warning: Invalid handleref: wanted code 4, got (1.7.0)
ERROR: Invalid LTYPE.dash x 61
ERROR: Invalid LTYPE.dash x 215
We just changed BL to signed. revert that and add a seperate BLd to represent the two such dxf ranges.
BL as signed is a problem for vcount/rcount overflow detection with negative values.
When open the crafted dwg
file , it could tigger null point dereference
in dwg2svg2
Let's see the gdb output
Program received signal SIGSEGV, Segmentation fault.
0x00000000005fc91c in dwg_obj_block_control_get_block_headers (ctrl=0xa51e30 <g_dwg+3088>, error=<optimized out>) at dwg_api.c:17897
17897 ptx[i] = ctrl->block_headers[i];
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────────────────────────────
*RAX 0x7ffff7f6c800 ◂— 0xbebebebebebebebe
*RBX 0xa51e30 (g_dwg+3088) —▸ 0x60800000bfa0 ◂— 0x0
*RCX 0x7ffff7f6c800 ◂— 0xbebebebebebebebe
RDX 0x0
RDI 0x0
RSI 0x0
R8 0x0
*R9 0xa51e50 (g_dwg+3120) ◂— 0x0
*R10 0x14a3ca
*R11 0x7ffff7f8c818 ◂— 0x0
*R12 0x7ffff7f6c800 ◂— 0xbebebebebebebebe
*R13 0x4002
*R14 0x7fffffffe280 ◂— 0x41b58ab3
R15 0x0
*RBP 0x7fffffffe210 —▸ 0x7fffffffe300 —▸ 0x7fffffffe330 —▸ 0x7fffffffe3e0 —▸ 0x71ed30 (__libc_csu_init) ◂— ...
*RSP 0x7fffffffe1f0 ◂— 0x0
*RIP 0x5fc91c (dwg_obj_block_control_get_block_headers+217) ◂— mov rdx, qword ptr [rdx]
──────────────────────────────────────────────────────────────────────────────────────────[ DISASM ]───────────────────────────────────────────────────────────────────────────────────────────
► 0x5fc91c <dwg_obj_block_control_get_block_headers+217> mov rdx, qword ptr [rdx]
0x5fc91f <dwg_obj_block_control_get_block_headers+220> mov rdi, rcx
0x5fc922 <dwg_obj_block_control_get_block_headers+223> mov r8, rcx
0x5fc925 <dwg_obj_block_control_get_block_headers+226> shr r8, 3
0x5fc929 <dwg_obj_block_control_get_block_headers+230> cmp byte ptr [r8 + 0x7fff8000], 0
0x5fc931 <dwg_obj_block_control_get_block_headers+238> je dwg_obj_block_control_get_block_headers+245 <0x5fc938>
↓
0x5fc938 <dwg_obj_block_control_get_block_headers+245> mov qword ptr [rcx], rdx
0x5fc93b <dwg_obj_block_control_get_block_headers+248> add rcx, 8
0x5fc93f <dwg_obj_block_control_get_block_headers+252> cmp rcx, r11
0x5fc942 <dwg_obj_block_control_get_block_headers+255> jne dwg_obj_block_control_get_block_headers+164 <0x5fc8e7>
↓
0x5fc8e7 <dwg_obj_block_control_get_block_headers+164> mov rdx, rcx
───────────────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]───────────────────────────────────────────────────────────────────────────────────────
17892 {
17893 BITCODE_BS i;
17894 *error = 0;
17895 for (i=0; i < ctrl->num_entries; i++)
17896 {
► 17897 ptx[i] = ctrl->block_headers[i];
17898 }
17899 return ptx;
17900 }
17901 else
17902 {
───────────────────────────────────────────────────────────────────────────────────────────[
pwndbg> p ptx
$1 = (dwg_object_ref **) 0x7ffff7f6c800
pwndbg> p ctrl->block_headers
$2 = (Dwg_Object_Ref **) 0x0
pwndbg> bt
#0 0x00000000005fc91c in dwg_obj_block_control_get_block_headers (ctrl=0xa51e30 <g_dwg+3088>, error=<optimized out>) at dwg_api.c:17897
#1 0x0000000000403d88 in output_SVG (dwg=0xa51220 <g_dwg>) at dwg2svg2.c:358
#2 0x0000000000401af9 in test_SVG (filename=0x7fffffffe73a "segment_poc") at dwg2svg2.c:90
#3 0x0000000000404656 in main (argc=2, argv=0x7fffffffe4c8) at dwg2svg2.c:479
#4 0x00007ffff67b7830 in __libc_start_main (main=0x403fa3 <main>, argc=2, argv=0x7fffffffe4c8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe4b8) at ../csu/libc-start.c:291
#5 0x0000000000401919 in _start ()
pwndbg>
As you can see , crash in
ptx[i] = ctrl->block_headers[i];
and null point dereference
is 0 , so null point dereference
。
The Vulnerability is that dwg_obj_block_control_get_block_headers
in dwg_api.c
don't check the ctrl->block_headers
.
dwg_object_ref **
dwg_obj_block_control_get_block_headers(const dwg_obj_block_control *restrict ctrl,
int *restrict error)
{
dwg_object_ref **ptx = (dwg_object_ref**)
malloc(ctrl->num_entries * sizeof(Dwg_Object_Ref *));
if (ptx)
{
BITCODE_BS i;
*error = 0;
for (i=0; i < ctrl->num_entries; i++)
{
ptx[i] = ctrl->block_headers[i];
}
return ptx;
}
else
{
*error = 1;
LOG_ERROR("%s: null malloc", __FUNCTION__)
return NULL;
}
}
To fix it, please verify the ctrl->block_headers before use it.
The poc file
https://gitee.com/hac425/fuzz_data/blob/master/poc.dwg
The few new/delete/free functions from the dwg_api are basically useless,
as they don't add/delete the entity to the DWG. We need to add a Dwg_Object
and the associated Dwg_Object_Entity and then the Dwg_Entity_CIRCLE.
Same for delete.
See encode.c for dwg_add_##ENTITY for the proper API, but these are untested (waiting for dwgwrite/dxf2dwg).
Use dwg_add_##ENTITY and dwg_free_object() instead.
Add these to the header, and document it.
with cmdline programs acting on really big files, free needs longer than processing the file.
e.g. with a 42MB DWG file, decode needs 40s and free >3m.
Add a flag to opts to skip it (0x20
is the next), used by the cmdline apps. The kernel is much faster and better freeing it.
Additionally think of replacing the linear search in object_refs with a hashmap, like in the benegon branch. But write it by myself for LICENSE reasons, and it can be much better then the simple Android hashmap.
Timings: -O2 linear: > 2m, hash: 5s.
Hi compiled and ran Libredwg and am trying to read some of our dwgs, I am unfortunately not a machine were I can anonymize the DWG so I can't upload it, does this error make senses without it ?
Drawing was made using Autocad 2016
add -fvisibility=hidden
, and explicitly mark the public functions as EXPORT via
__attribute__((visibility("default")))
resp. __declspec(dllexport)
mimics windows default visibility
otherwise we might get into trouble later when changing internal functions.
The HANDSEED DXF value never matches the HANDSEED DWG value.
See also https://sourceforge.net/p/libdwg/tickets/8/
$ grep -A2 HANDSEED td/Drawing_2000.dxf | tail -n1
6DF
$ grep HANDSEED Drawing_2000.log
HANDSEED: 0x5bc [RL 0]
HANDSEED: HANDLE(0.2.5BC) absolute:5BC [0]
printf "%x", 0x6df - 0x5bc => 0x123
This is libredwg unrelated and seems to be a DwgFiler/DxfFiler oddity.
But HANDSEED is a handle and needs to printed as hex.
make it two functions, add as public API, which initializes the empty object. go away with the current add functions, which reads fields from an empty zero stream.
If possible add default values already at add, like from a DEFAULT { FIELD_VALUE(field) = 1.0; }
block. rename IF_ENCODE_FROM_EARLIER
to DEFAULT
. It must be the first block in a spec, and probably it needs to be mandatory to close the add function and start the decode function.
Then reading the fields from the dwg is a separate function. This is needed for all in_* modules and dwg_encode.
This separation is also needed for ACAD_TABLE, jumping with r2010+ to dwg_ ##action _TABLECONTENT(dat,obj);
without the initialization (add) code.
dejagnu itself is probed fine.
[00:01:15] checking dejagnu.h usability... yes
[00:01:15] checking dejagnu.h presence... yes
[00:01:15] checking for dejagnu.h... yes
e.g. https://ci.appveyor.com/project/rurban/libredwg/build/0.4.25/job/cprh3drj2u830jnm#L2249
libtool: link: gcc -fno-strict-aliasing -Wall -Wextra -Wundef -Wwrite-strings -Wpointer-arith -Wmissing-declarations -Wredundant-decls -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-missing-field-initializers -Wno-cast-align -Wformat=2 -Wformat-nonliteral -Wformat-security -Wsign-compare -Wstrict-aliasing -Wshadow -Winline -Wpacked -Wmissing-format-attribute -Wmissing-noreturn -Winit-self -Wmissing-include-dirs -Warray-bounds -Wreturn-type -Wswitch-enum -Wswitch-default -Wduplicated-cond -Wlogical-op -Wnull-dereference -Wdouble-promotion -Wnested-externs -Wmissing-prototypes -Wstrict-prototypes -Wdeclaration-after-statement -Wimplicit-function-declaration -Wold-style-definition -Wjump-misses-init -Wno-error=unused-variable -Wno-error=unused-parameter -Wno-error=unused-but-set-variable -Wno-error=missing-field-initializers -Wno-error=cast-align -g -o .libs/3dsolid.exe 3dsolid.o ../../src/.libs/libredwg.dll.a -L/usr/local/lib
3dsolid.o: In function `api_process':
/cygdrive/c/projects/libredwg/testsuite/testcases/3dsolid.c:26: undefined reference to `pass'
/cygdrive/c/projects/libredwg/testsuite/testcases/3dsolid.c:28: undefined reference to `fail'
/cygdrive/c/projects/libredwg/testsuite/testcases/3dsolid.c:34: undefined reference to `pass'
/cygdrive/c/projects/libredwg/testsuite/testcases/3dsolid.c:36: undefined reference to `fail'
...
See https://gcc.gnu.org/bugzilla//show_bug.cgi?id=63613
we need to add -fgnu89-inline
for consistency
include/dwg.h: BITCODE_BL frozen_layer_count;
include/dwg.h: BITCODE_BL instance_count; /* 91 Instance count for a custom class */
include/dwg.h: BITCODE_BL owned_obj_count;
include/dwg.h: BITCODE_BL owned_object_count;
include/dwg.h: BITCODE_BS attr_def_count;
include/dwg.h: BITCODE_BS m_vert_count;
include/dwg.h: BITCODE_BS n_vert_count;
include/dwg.h: BITCODE_RL insert_count;
include/dwg.h:dwg_get_entity_count(const Dwg_Data *);
include/dwg.h:dwg_get_layer_count(const Dwg_Data *);
include/dwg.h:dwg_get_object_count(const Dwg_Data *dwg);
include/dwg.h:dwg_get_object_object_count(const Dwg_Data *dwg);
e.g. dwg_get_numobjects, dwg_get_numentities, numfrozen_layers, ...
we have way more num* fields than _count.
Hi, I installed all the dependencies the README mentioned, but when I excute "./configure --enable-trace --disable--write --disable-shared", still an error occured, please check it below:
checking for swig... /usr/bin/swig
checking SWIG version... 2.0.12
checking for SWIG library... /usr/share/swig2.0
checking for a Python interpreter with version >= 2.7... python
checking for python... /root/.pyenv/shims/python
checking for python version... 2.7
checking for python platform... linux2
checking for python script directory... ${prefix}/lib/python2.7/site-packages
checking for python extension module directory... ${exec_prefix}/lib/python2.7/site-packages
checking for python2.7... (cached) /root/.pyenv/shims/python
checking for a version of Python >= '2.1.0'... yes
checking for the distutils Python package... yes
checking for Python include path... -I/root/.pyenv/versions/2.7.9/include/python2.7
checking for Python library path...
ac_python_libdir=/root/.pyenv/versions/2.7.9/lib/python2.7/config
ac_python_library=libpython2.7.a
ac_python_soname=libpython2.7.a
use the --enable-frameworked shared library
-L/root/.pyenv/versions/2.7.9/lib/python2.7/config -lpython2.7
checking for Python site-packages path... /root/.pyenv/versions/2.7.9/lib/python2.7/site-packages
checking python extra libraries... -lpthread -ldl -lutil
checking python extra linking flags... -Xlinker -export-dynamic
checking consistency of all components of python development environment... no
configure: error: in `/home/odoo/new/libredwg-0.5.0.1176':
configure: error:
Could not link test program to Python. Maybe the main Python library has been
installed in some non-standard library path. If so, pass it to configure,
via the LDFLAGS environment variable.
Example: ./configure LDFLAGS="-L/usr/non-standard-path/python/lib"
============================================================================
ERROR!
You probably have to install the development version of the Python package
for your distribution. The exact name of this package varies among them.
============================================================================
but I already installed python-dev, and I excute "./configure LDFLAGS="-L/root/.pyenv/versions/2.7.9/lib/python2.7" PYTHON="/root/.pyenv/shims/python" --enable-trace", same error still happed. Here's my config.log, anything wrong about it?
config.log
it's getting absurd, 50MB for the lib.
use more generic helper functions, instead of inlining everything.
I has downloaded the zip, I want to use this library in windows. I created a C++ project and add the dwg.h into the head like this:
extern "C"{
#include <dwg.h>
}
and I copyed codes like this:
void main(){
const char * inputFilename = "XXXX.dwg";
Dwg_Data dwg = new Dwg_Data();
int errno = dwg_read_file((char *)inputFilename, dwg);
if (errno) {
fprintf(stderr, "Could not open DWG. Returned error code: $d\n", errno);
delete dwg;
}
Dwg_Object_BLOCK_CONTROL * ctrl = dwg->object[0].tio.object->tio.BLOCK_CONTROL;
dumpBlock(ctrl->model_space);
dumpBlock(ctrl->paper_space);
for (int i = 0; i < ctrl->num_entries; i++) {
dumpBlock(ctrl->block_headers[i]);
}
dwg_free(dwg);
}
but there are many bugs. what's wrong? Is that I can't add the dwg.h directly??? I'm not practice in writing codes.
They are created fine, for python and perl (in branch work/perl
), but then they seem to miss even the most basic functionality.
I'd like to use them for some basic UI DWG viewer of the internal structures.
Maybe switch over to valabind vapi bindings for most scripting languages and C#/C++: c++, rust, go, node, java, python, perl, ruby, php, autolisp (via ARX). With a proper vapi file the generated swig file also looks much better than now.
The dwg2dxf output extra newline for every group code and group value in dxf file, so cannot open the DXF file generated by dwg2dxf.
there exist various api functions to change the number of some elements without changing the associated array itself, e.g. dwg_ent_polyline_mesh_set_num_n_verts without setting the n_verts array.
all the set_num_ api functions need to go, and maybe add array add
(at the end) and delete
(at some index).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.