diff --git a/src/fonts.js b/src/fonts.js
index 02c28a3c2..aa96be569 100644
--- a/src/fonts.js
+++ b/src/fonts.js
@@ -3341,7 +3341,8 @@ var Font = (function FontClosure() {
         }
       }
 
-      function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
+      function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
+                             hintsValid) {
         if (sourceEnd - sourceStart <= 12) {
           // glyph with data less than 12 is invalid one
           return 0;
@@ -3361,8 +3362,10 @@ var Font = (function FontClosure() {
           j += 2;
         }
         // skipping instructions
+        var instructionsStart = j;
         var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
         j += 2 + instructionsLength;
+        var instructionsEnd = j;
         // validating flags
         var coordinatesLength = 0;
         for (var i = 0; i < flagsCount; i++) {
@@ -3385,6 +3388,17 @@ var Font = (function FontClosure() {
           // not enough data for coordinates
           return 0;
         }
+        if (!hintsValid && instructionsLength > 0) {
+          dest.set(glyf.subarray(0, instructionsStart), destStart);
+          dest.set([0, 0], destStart + instructionsStart);
+          dest.set(glyf.subarray(instructionsEnd, glyphDataLength),
+                   destStart + instructionsStart + 2);
+          glyphDataLength -= instructionsLength;
+          if (glyf.length - glyphDataLength > 3) {
+            glyphDataLength = (glyphDataLength + 3) & ~3;
+          }
+          return glyphDataLength;
+        }
         if (glyf.length - glyphDataLength > 3) {
           // truncating and aligning to 4 bytes the long glyph data
           glyphDataLength = (glyphDataLength + 3) & ~3;
@@ -3441,7 +3455,7 @@ var Font = (function FontClosure() {
       }
 
       function sanitizeGlyphLocations(loca, glyf, numGlyphs,
-                                      isGlyphLocationsLong) {
+                                      isGlyphLocationsLong, hintsValid) {
         var itemSize, itemDecode, itemEncode;
         if (isGlyphLocationsLong) {
           itemSize = 4;
@@ -3483,7 +3497,7 @@ var Font = (function FontClosure() {
           }
 
           var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
-                                        newGlyfData, writeOffset);
+                                        newGlyfData, writeOffset, hintsValid);
           writeOffset += newLength;
           itemEncode(locaData, j, writeOffset);
           startOffset = endOffset;
@@ -3648,7 +3662,7 @@ var Font = (function FontClosure() {
         0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
         -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
         1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
-        0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -2, 0, -2, -2,
+        0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,
         0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
         -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
         -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -3801,33 +3815,22 @@ var Font = (function FontClosure() {
         foldTTTable(table, content);
       }
 
-      function addTTDummyFunctions(table, ttContext, maxFunctionDefs) {
-        var content = [table.data];
-        if (!ttContext.tooComplexToFollowFunctions) {
-          var undefinedFunctions = [];
-          for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
-            if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) {
-              continue;
-            }
-            undefinedFunctions.push(j);
-            if (j >= maxFunctionDefs) {
-              continue;
-            }
-            // function is used, but not defined
-            if (j < 256) {
-              // creating empty one [PUSHB, function-id, FDEF, ENDF]
-              content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
-            } else {
-              // creating empty one [PUSHW, function-id, FDEF, ENDF]
-              content.push(
-                new Uint8Array([0xB8, j >> 8, j & 255, 0x2C, 0x2D]));
-            }
+      function checkInvalidFunctions(ttContext, maxFunctionDefs) {
+        if (ttContext.tooComplexToFollowFunctions) {
+          return;
+        }
+        for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
+          if (j > maxFunctionDefs) {
+            warn('TT: invalid function id: ' + j);
+            ttContext.hintsValid = false;
+            return;
           }
-          if (undefinedFunctions.length > 0) {
-            warn('TT: undefined functions: ' + undefinedFunctions);
+          if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
+            warn('TT: undefined function: ' + j);
+            ttContext.hintsValid = false;
+            return;
           }
         }
-        foldTTTable(table, content);
       }
 
       function foldTTTable(table, content) {
@@ -3854,7 +3857,8 @@ var Font = (function FontClosure() {
           functionsDefined: [],
           functionsUsed: [],
           functionsStackDeltas: [],
-          tooComplexToFollowFunctions: false
+          tooComplexToFollowFunctions: false,
+          hintsValid: true
         };
         if (fpgm) {
           sanitizeTTProgram(fpgm, ttContext);
@@ -3863,8 +3867,9 @@ var Font = (function FontClosure() {
           sanitizeTTProgram(prep, ttContext);
         }
         if (fpgm) {
-          addTTDummyFunctions(fpgm, ttContext, maxFunctionDefs);
+          checkInvalidFunctions(ttContext, maxFunctionDefs);
         }
+        return ttContext.hintsValid;
       }
 
       // Check that required tables are present
@@ -3916,6 +3921,25 @@ var Font = (function FontClosure() {
         tables.push(table);
       }
 
+      // Ensure the hmtx table contains the advance width and
+      // sidebearings information for numGlyphs in the maxp table
+      font.pos = (font.start || 0) + maxp.offset;
+      var version = int32(font.getBytes(4));
+      var numGlyphs = int16(font.getBytes(2));
+      var maxFunctionDefs = 0;
+      if (version >= 0x00010000 && maxp.length >= 22) {
+        font.pos += 14;
+        var maxFunctionDefs = int16(font.getBytes(2));
+      }
+
+      var hintsValid = sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
+      if (!hintsValid) {
+        tables.splice(tables.indexOf(fpgm), 1);
+        fpgm = null;
+        tables.splice(tables.indexOf(prep), 1);
+        prep = null;
+      }
+
       var numTables = tables.length + requiredTables.length;
 
       // header and new offsets. Table entry information is appended to the
@@ -3930,28 +3954,16 @@ var Font = (function FontClosure() {
       // of missing tables
       createOpenTypeHeader(header.version, ttf, numTables);
 
-      // Ensure the hmtx table contains the advance width and
-      // sidebearings information for numGlyphs in the maxp table
-      font.pos = (font.start || 0) + maxp.offset;
-      var version = int32(font.getBytes(4));
-      var numGlyphs = int16(font.getBytes(2));
-      var maxFunctionDefs = 0;
-      if (version >= 0x00010000 && maxp.length >= 22) {
-        font.pos += 14;
-        var maxFunctionDefs = int16(font.getBytes(2));
-      }
-
       sanitizeMetrics(font, hhea, hmtx, numGlyphs);
 
-      sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
-
       if (head) {
         sanitizeHead(head, numGlyphs, loca.length);
       }
 
       var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
       if (head && loca && glyf) {
-        sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
+        sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong,
+                               hintsValid);
       }
 
       var emptyGlyphIds = [];
diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore
index 0dd45793f..3872774e3 100644
--- a/test/pdfs/.gitignore
+++ b/test/pdfs/.gitignore
@@ -48,3 +48,4 @@
 !noembed-sjis.pdf
 !vertical.pdf
 !issue2099-1.pdf
+!issue2956.pdf
diff --git a/test/pdfs/issue2956.pdf b/test/pdfs/issue2956.pdf
new file mode 100644
index 000000000..8865e9960
Binary files /dev/null and b/test/pdfs/issue2956.pdf differ
diff --git a/test/test_manifest.json b/test/test_manifest.json
index 9464cba5f..fb365c296 100644
--- a/test/test_manifest.json
+++ b/test/test_manifest.json
@@ -1120,6 +1120,12 @@
       "rounds": 1,
       "type": "eq"
     },
+    {  "id": "issue2956",
+      "file": "pdfs/issue2956.pdf",
+      "md5": "d8f68cbbb4bf54cde9f7f878acb6d7cd",
+      "rounds": 1,
+      "type": "eq"
+    },
     {  "id": "issue2177-eq",
       "file": "pdfs/issue2177.pdf",
       "md5": "48a808278bf31de8414c4e03ecd0900a",